为什么第二个命令有效,为什么不先?有什么区别?

时间:2015-08-11 17:15:04

标签: bash unix ksh

我在shell脚本中遇到了以下奇怪的问题。

当我执行如下操作时,它不起作用:

excom='/Development/temp_try/testing/\* -o -path /Development/temp_try/testing1/\*'
findcom=$(find /Development/temp_try ! \( -path $excom \) -type f \( ! -name \*.HPSEPFQDN.\* ! -name \*.HPSEPIPCHG.\* \) -exec grep -lF "corp.abc.com" {} \;)

如果我执行如下所示,它可以正常工作:

findcom=$(find /Development/temp_try ! \( -path /Development/temp_try/testing/\* -o -path /Development/temp_try/testing1/\* \) -type f \( ! -name \*.HPSEPFQDN.\* ! -name \*.HPSEPIPCHG.\* \) -exec grep -lF "corp.abc.com" {} \;)

第一个输出是:

/Development/temp_try/f1
/Development/temp_try/f2
/Development/temp_try/f3
/Development/temp_try/f4
/Development/temp_try/f5
/Development/temp_try/f6
/Development/temp_try/f7
/Development/temp_try/f8
/Development/temp_try/try10
/Development/temp_try/log_test
/Development/temp_try/try10v
/Development/temp_try/try10v1
/Development/temp_try/try10j
/Development/temp_try/try10j1
/Development/temp_try/testing1/f1
/Development/temp_try/testing1/f2
/Development/temp_try/testing1/f3
/Development/temp_try/testing/test1/f1
/Development/temp_try/testing/test1/f2
/Development/temp_try/testing/test1/f3
/Development/temp_try/testing/test1/f4
/Development/temp_try/testing/test1/f5
/Development/temp_try/testing/test1/f6
/Development/temp_try/testing/test1/f7
/Development/temp_try/testing/test1/f8
/Development/temp_try/testing/f1
/Development/temp_try/testing/f2
/Development/temp_try/testing/f3
/Development/temp_try/testing/f4
/Development/temp_try/testing/f5
/Development/temp_try/testing/f6
/Development/temp_try/testing/f7
/Development/temp_try/testing/f8
/Development/temp_try/try10j1_working
/Development/temp_try/try11
/Development/temp_try/try11_original
/Development/temp_try/try8

其中第二个输出是:

/Development/temp_try/f1
/Development/temp_try/f2
/Development/temp_try/f3
/Development/temp_try/f4
/Development/temp_try/f5
/Development/temp_try/f6
/Development/temp_try/f7
/Development/temp_try/f8
/Development/temp_try/try10
/Development/temp_try/log_test
/Development/temp_try/try10v
/Development/temp_try/try10v1
/Development/temp_try/try10j
/Development/temp_try/try10j1
/Development/temp_try/try10j1_working
/Development/temp_try/try11
/Development/temp_try/try11_original
/Development/temp_try/try8

第二个完全排除了第一个没有的目录。我不知道他们俩如何不同......

感谢您的回答和评论,现在我明白了这个问题,可以解决问题。

#!/usr/bin/ksh

filepath="/Development/temp_try"
searchstring="corp.abc.com"

while read exfile
do
lasc=${exfile##${exfile%%?}}
if [ "$lasc" = "/" ]; then
exfile="$exfile*"
fi
if [ "$excom" = "" ]; then
excom="$exfile"
else
#excom="$excom -o -path '$exfile'"
set -A excom "$excom" '-o' '-path' "$exfile"
fi
done <input4


echo "The exclude command is ${excom[@]}"
findcom=$(find $filepath ! \( -path "${excom[@]}" \) -type f \( ! -name \*.HPSEPFQDN.\* ! -name \*.HPSEPIPCHG.\* \) -exec grep -lF $searchstring {} \;)
for filename in $findcom
do
echo $filename
done

我的input4文件包含以下行:

/Development/temp_try/testing/
/Development/temp_try/testing1/

2 个答案:

答案 0 :(得分:3)

不要将命令行(完全或部分)存储在简单变量中,因为它在shell中进行变量扩展时会产生许多问题。

最好存储在像这样的shell数组中

excom=('/Development/temp_try/testing/*' -o -path '/Development/temp_try/testing1/*')
findcom=$(find /Development/temp_try ! \( -path "${excom[@]}" \) -type f \( ! -name \*.HPSEPFQDN.\* ! -name \*.HPSEPIPCHG.\* \) -exec grep -lF "corp.abc.com" {} \;)

答案 1 :(得分:3)

在单引号字符串中,\没有特殊意义。所以

的结果
excom='/Development/temp_try/testing/\* -o -path /Development/temp_try/testing1/\*'

excom的值将包含两个反斜杠字符。

反斜杠字符在文件名扩展中并不特殊,因此当$excom的值为filename-expanded和wordsplit(因为它的扩展未引用)时,反斜杠字符仍然是普通字符。所以扩大了

find /Development/temp_try ! \( -path $excom \) ...

有文字:

find
/Development/temp_try
!
(
-path
/Development/temp_try/testing/\*
-o
-path
/Development/temp_try/testing1/\*

没有任何内容与模式/Development/temp_try/testing/\*匹配,因为您的文件名不包含反斜杠。

当您定义excom时,您是否遗漏了反斜杠:

excom='/Development/temp_try/testing/* -o -path /Development/temp_try/testing1/*'

然后在调用find时扩展文件名模式。在这种情况下,find /Development/temp_try ! \( -path $excom \) ...会扩展为:

find
/Development/temp_try
!
(
-path
/Development/temp_try/testing/f1
/Development/temp_try/testing/f2
/Development/temp_try/testing/f3
...

这也不是你想要的,因为-path谓词需要后跟一个模式,而不是文件名列表。

因此,您需要将excom的值作为引用词列表传递。在bash中唯一简单的方法是使用数组,因为您可以将数组扩展为带引号的数组值列表:

excom=("/Development/temp_try/testing/*"
       -o -path "/Development/temp_try/testing1/*")
findcom=$(find /Development/temp_try ! \( -path "${excom[@]}" \) \
          -type f \( ! -name "*.HPSEPFQDN.*" ! -name "*.HPSEPIPCHG."* \) \
          -exec grep -lF "corp.abc.com" {} \;)

findcom的定义(未引用)假定-exec grep命令生成的文件名不会在其名称中包含空格或模式元字符。通常,这是不是一个安全的假设。)