我希望我的 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
将会-quit
find
第一场比赛后退出,因此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 $var
shell 会将其分解为两个单独的项目hello
,world
并且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