为什么第二个命令有效,为什么不是第一个?有什么不同?

Why the second command works and why not first? what is the difference?

我在 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/

不要将命令行(全部或部分)存储在简单变量中,因为它会在 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" {} \;)

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

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

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

反斜杠字符在文件名扩展中并不特殊,所以当$excom的值被文件名扩展和分词时(因为它的扩展没有被引用),反斜杠字符仍然是普通字符。所以展开

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 命令生成的文件名的名称中不会包含空格或模式元字符。一般来说,这不是安全假设。)