Shell 多个表达式是否可以找到合适的工具?
我有很多目录,其中包含一组程序的输出和数据文件。每个目录都有相似的内容,我的go还有4个级别。我的目标是识别所有目录,这些目录在任何子目录中都有核心文件,并且具有大于1k的给定名称模式的日志文件。日志文件与核心文件不在同一个子目录中 我可以独立地编写用于每个目标的find命令,但我所有的组合表达式的尝试都无法产生任何结果 第一命令:Shell 多个表达式是否可以找到合适的工具?,shell,unix,find,Shell,Unix,Find,我有很多目录,其中包含一组程序的输出和数据文件。每个目录都有相似的内容,我的go还有4个级别。我的目标是识别所有目录,这些目录在任何子目录中都有核心文件,并且具有大于1k的给定名称模式的日志文件。日志文件与核心文件不在同一个子目录中 我可以独立地编写用于每个目标的find命令,但我所有的组合表达式的尝试都无法产生任何结果 第一命令: find \( \( -path "./SESS*" -name "log_snap_*" \) \( -size +1k\) \) 第二命令: find \(
find \( \( -path "./SESS*" -name "log_snap_*" \) \( -size +1k\) \)
第二命令:
find \( -path "./SESS" -regex "*core.[0-9]+\(.gz)*" \)
如何编写一个测试来识别满足这两个标准的目录?对这个问题有多种合理的解释——请参阅下面基于不同答案的答案
假设你指的是“任一”标准。。。 请考虑以下设置:
files_empty=(
SESS/log_snap_1234 # ignored because not more than 1k in size
SESS/ignoreme # ignored because not matching either pattern
SESS/core.13.gz # expected to be in results
SESS/core.13 # expected to be in results
)
files_full=(
SESS/log_snap_2345 # expected to be in results
)
{ tempdir=$(mktemp -d /tmp/test.XXXXXX) && cd "$tempdir"; } || exit
mkdir -p SESS bad
touch "${files_empty[@]}"
for f in "${files_full[@]}"; do
dd if=/dev/zero of="$f" bs=1k count=2
done
如果在使用上述方法创建测试环境后,我们在GNUfind
中运行以下操作:
find ./SESS \
'(' '(' -name 'log_snap_*' -size +1k ')' \
-o '(' -regextype posix-extended -regex ".*core[.][0-9]+([.]gz)?" ')' \
')' -print
…我们得到了正确的结果:
./SESS/log_snap_2345
./SESS/core.13
./SESS/core.13.gz
那么,发生了什么变化
- 当您只需修改起始位置时,不要使用
过滤正在搜索的位置。当您运行-path
,它在find时-路径“/SESS/*”
下搜索所有地方,但当结果与
不匹配时就会丢弃;与只搜索您首先关心的目录相比,这是非常低效的/SESS/*
- 使用
指定或条件-o
- 当您想要的是后续测试之间的AND时,分组运算符或显式的
没有意义,因为这是隐式行为-a
- 明确指定最终操作(例如
)是一种非常好的形式。在您当前的情况下不是完全强制的,但在其他常见场景中是强制的(例如使用-print
);因此,养成习惯可以减少犯错的空间-prune
- 不允许正则表达式以
开头,因为*
表示“前面的项为零或多个”。在正则表达式的开头,没有优先项,因此此构造没有任何意义*
- 在正则表达式中,显式句点应写为
,因为裸[.]
表示“任意字符之一”
如果你真的是指“两者”标准。。。 对于这个部分,我们实际上不需要进入
find
。一个警告:我有意避免正确处理文件名包含文字换行符的情况。这是可能发生的。忽视它并不理想
无论如何,将两个shell函数作为两个不同的find
命令输出的替代:
find1_cmd() {
printf '%s\n' \
SESS/session_one/log_snap_1234 \
SESS/session_one/log_snap_4567 \
SESS/session_three/log_snap_8901
}
find2_cmd() {
printf '%s\n' \
SESS/session_one/core.1234.gz
SESS/session_four/core.5678.gz
}
我们只能在这两个目录中找到目录,如下所示:
prep() {
while IFS= read -r line; do
printf '%s\n' "${line%/*}" # remove the filename, leaving only the directory
done | sort -u # sort and uniq-ify the results
}
comm -12 <(find1_cmd | prep) <(find2_cmd | prep)
prep(){
当IFS=读取-r行时;执行
printf'%s\n'${line%/*}删除文件名,只保留目录
完成|排序-u#排序并统一结果
}
comm-12为什么所有嵌套的组都是?您只需要条件and,对吗?就这点而言,为什么find-path./SESS
而不是find./SESS
?后者的效率要高得多,因为它不会在只考虑每个结果的分支上递归。而且,-regex“*core。[0-9]+\(.gz)*”
实际上不是有效的regex。不能将*
作为正则表达式中的第一个字符,因为它表示“前一项的零个或多个”;在第一个位置,没有前面的项目。请参阅我的答案,了解问题的结构——显示创建测试环境的代码,然后显示给定该测试环境的预期输出,然后显示给定该测试环境的实际输出。定义进一步讨论了这一点……如果您提供了这样的代码——进行设置,并给我们预期的/预期的输出——那么您的预期逻辑将不会有任何猜测或解释。是的,我确实需要所有标准的and,而不是or。我想确定具有核心文件和某些特定大小的日志文件的顶级会话_xxxx目录。