2017-07-24 31 views
1

我正在尝试使用查找结合大括号扩展和eval来查找子文件夹中的多个文件。当我这样做:

nr1=1001 
nr2=1500 
eval ls abc*_{$nr1..$nr2}* 

它的工作原理,我期望它。然而,当我尝试这样:

eval find path/to/folder -name "abc*_{$nr1..$nr2}*" 

我得到的错误信息:

find: paths must precede expression: abc*_{1001..1500}* 
Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression] 

我已经有和没有评估和似乎没有任何工作尝试不同的组合。基本上我需要find命令来处理使用变量的大括号扩展和文件名中的其他元字符。虽然我不一定需要使用eval,但我必须承认我并不完全理解它。

+0

与'find'你可以做'-name “* PAT1” -o -name “* PAT2”'...等等 –

+2

'-name'采用* single *模式,并且不支持大括号扩展。使用'eval',* best *的情况是,你最终得到一个像'find/path -name abc_1001 * abc_1002 * ...'这样的命令。 – chepner

回答

3

使用eval容易出错,包括在处理其他人选择名称的文件时引入安全漏洞。 Don't do it。 (除了这一般的告诫 - foo{1..3}扩展为正在运行的命令的三个独立参数,foo1,foo2foo3;在-name之后的find命令行上放置500个单独的参数就像听起来一样不可行;因此, t在传递给find -name的参数中使用该语法,即使是而没有eval)。

一个非eval基于相当于你的第一个命令是:

args=() 
for ((i=nr1; i<=nr2; i++)); do 
    args+=(abc*_"$i"*) 
done 
ls "${args[@]}" 

对于第二个命令,你最终的东西更接近:

find_args=() 
for ((i=nr1; i<=nr2; i++)); do 
    find_args+=(-name "abc*_${i}*" -o) 
done 
find path/to/folder '(' "${find_args[@]}" -false ')' -print 

注意,-falsefind_args阵列中存储的-name foo -o name bar -o name baz参数流中填写最后一个-o的右侧。


然而,在这两种情况下,你运行大范围的命令行中运行的空间不足的风险(你的原代码运行以及风险!)。我建议过滤的数值范围运行find操作后:

digits_re='_([[:digit:]]+)([^[:digit:]]|$)' 
while IFS= read -r -d '' filename; do 
    dirname=${filename%/*} 
    basename=${filename##*/} 
    if [[ $basename =~ $digits_re ]]; then 
    number=${BASH_REMATCH[1]} 
    if ((number >= nr1 && number <= nr2)); then 
     printf '%q\n' "$filename" # for human consumption 
     # use '%s\0' instead for a NUL-delimited stream for programmatic use. 
    fi 
    fi 
done < <(find path/to/folder -name 'abc*_[[:digit:]]*' -print0) 
+0

谢谢,第二个选项应该起作用,因为find的输出存储在一个带有$()的变量中。 – longibongi

+0

使用'$()'捕获'find'的输出实际上是不合理和安全的。信息'$()'的域可以捕获匹配可能的文件名中的字符域,所以你不可能确定你认为**是两个名字之间的分隔符实际上是这样的。 –

+0

考虑用'touch $'foo \ nbar''创建的文件 - 你不能分辨新行是否意味着'bar'是一个完全不同的文件名,或者它是同一个文件名称的一部分。 –

相关问题