在 find 命令后使用连接器

Jos*_*muk 10 command-line find

我希望我的 bash 仅在找到某些内容时才使用 find 命令打印“找到”。但是使用 && 无济于事:即使什么也没找到,我也会打印“找到”。例子:

$ pwd
/data/data/com.termux/files/home/test/test1/test4
$ ls
xaa  xab
$ find . -name xac && echo 'found'
found
$ find . -name xaa && echo 'found'
./xaa
found
Run Code Online (Sandbox Code Playgroud)

mur*_*uru 18

你可以让find自己打印found

find . -name xac -printf "found\n" -quit
Run Code Online (Sandbox Code Playgroud)

-quitfind 后的首场比赛退出,因此found仅在最打印一次。

在 Unix 和 Linux 上的一个类似线程上(没有找到任何东西时 make find 失败),我曾经在没有找到任何东西时grep -qz返回一个非零退出状态find

find /some/path -print0 -quit | grep -qz .
Run Code Online (Sandbox Code Playgroud)

您可以使用它来构造复合命令&&或使用if

find /some/path -print0 -quit | grep -qz . && echo found
Run Code Online (Sandbox Code Playgroud)


Ser*_*nyy 13

muru 的答案是合适的,非常适合我们想要在找到文件后打印某些内容的情况。对于我们想要执行外部命令的一般情况,例如echo,我们可以使用-exec标志。

$ find . -name 'xac' -exec echo "I found " {} \; -quit             
I found  ./xac
Run Code Online (Sandbox Code Playgroud)

{}部分通过文件名之间的命令-exec\;作为参数。注意\之前;- 它可以防止 shell 误解它吗?在 shell 中,结束分号表示命令结束,但是当用 slash 转义时,shell 会将其视为要传递给findcommand 的文字文本,并在 find 命令中用作结束-exec标志的参数。


为了构造if found do this; else do that排序条件,我们可以使用命令替换$()test命令(又名[):

$ [ "x$(find . -name 'noexist' -print -quit)" != "x" ] && echo "found" || echo "not found"                                                                                              
not found

$ [ "x$(find . -name 'xac' -print -quit)" != "x" ] && echo "found" || echo "not found"                                                                                                  
found
Run Code Online (Sandbox Code Playgroud)

解决丹的评论

丹在评论中问道:

echo "I found {}" 会不会比 echo "I found " {} 更好?也许对于 echo 来说没问题,但是如果有人复制命令并将 echo 替换为另一个命令,他们可能会遇到问题

我们先来了解一下问题。通常,在 shell 中有分词的概念,这意味着未加引号的变量和位置参数将被扩展并被视为单独的项目。例如,如果您有变量var并且它包含hello world文本,那么当您执行touch $var此操作时,shell 会将其分解为两个单独的项目helloworld并且touch会理解为好像您正在尝试创建 2 个单独的文件;如果你这样做了touch "$var",那么 shell 将被hello world视为一个单元,并且touch只会创建一个文件。重要的是要了解这仅是由于 shell 的工作方式而发生的。

相比之下,find不会受到这种行为的影响,因为命令是由find自身处理并由execvp()系统调用执行的,因此不涉及 shell。虽然花括号在 shell 中确实有特殊意义,因为它们出现在find命令的中间,而不是开头,所以在这种情况下,它们对 shell 没有特殊意义。这是一个例子。让我们创建一些困难的文件名并尝试将它们作为参数传递给stat命令。

$ touch with$'\t'tab.txt with$' 'space.txt with$'\n'newline.txt

$ find -type f -exec stat -c "%F" {} \; -print                                                                                                                         
regular empty file
./with?newline.txt
regular empty file
./with space.txt
regular empty file
./with?tab.txt
Run Code Online (Sandbox Code Playgroud)

如您所见,使用stat接收困难的文件名非常好find,这是建议在可移植脚本中使用它的主要原因之一,当您遍历目录树并希望对可能具有的文件名执行某些操作时尤其有用其中的特殊字符。因此,没有必要为在find.

当 shell 介入时,情况就不同了。有时您需要使用 shell 来处理文件名。在这种情况下,引用确实很重要,但重要的是要意识到这不是 find 的问题 - 是 shell 进行分词。

$ find -type f -exec bash -c "stat {}" sh \;   
stat: cannot stat './with': No such file or directory
sh: line 1: newline.txt: command not found
stat: cannot stat './with': No such file or directory
stat: cannot stat 'space.txt': No such file or directory
stat: cannot stat './with': No such file or directory
stat: cannot stat 'tab.txt': No such file or directory
Run Code Online (Sandbox Code Playgroud)

所以当我们在 shell 中引用时,它会起作用。但同样,这对 shell 很重要,而不是find.

$ find -type f -exec bash -c "stat -c '%F' '{}'" sh \;                                                                                                                 
regular empty file
regular empty file
regular empty file
Run Code Online (Sandbox Code Playgroud)