在 find 命令后使用连接器

在 find 命令后使用连接器

我希望我的 bash 仅在找到某些内容时才使用 find 命令打印“found”。但使用 && 没有帮助:即使什么也没找到,我也会打印“found”。示例:

$ 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

答案1

你可以让它find自行打印found

find . -name xac -printf "found\n" -quit

将会-quitfind 第一场比赛后退出,因此found最多只打印一次。

在有关 Unix 和 Linux 的类似主题中 (当未找到任何内容时,查找失败),grep -qz如果没有找到任何内容,我过去常常返回非零的退出状态find

find /some/path -print0 -quit | grep -qz .

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

find /some/path -print0 -quit | grep -qz . && echo found

答案2

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

$ find . -name 'xac' -exec echo "I found " {} \; -quit             
I found  ./xac

部分将文件名作为参数传递给和{}之间的命令。注意之前的- 可以防止 shell 误解它;在 shell 中,结束分号表示命令结束,但是当使用斜线转义时,shell 会将其视为要传递给命令的文字,并且对于 find 命令,它充当结束标志的参数。-exec\;\;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

回应 Dan 的评论

丹在评论问:

echo "I found {}" 难道不会比 echo "I found " {} 更好吗?对于 echo 来说,也许这样还行,但如果有人复制命令并用另一个命令替换 echo,他们可能会遇到问题

首先让我们了解一下这个问题。通常,在 shell 中有分词的概念,这意味着未加引号的变量和位置参数将被扩展并视为单独的项目。例如,如果您有一个变量var并且它包含hello world文本,则当您这样做时,touch $varshell 会将其分解为两个单独的项目helloworld并且touch会理解这就像您试图创建两个单独的文件一样;如果您这样做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

如您所见,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

因此当我们引用壳内,它将起作用。但同样,这对 shell 很重要,而不是find

$ find -type f -exec bash -c "stat -c '%F' '{}'" sh \;                                                                                                                 
regular empty file
regular empty file
regular empty file

相关内容