我希望我的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
我希望我的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
Answers:
您可以find
自己打印found
:
find . -name xac -printf "found\n" -quit
第一次比赛-quit
后将find
退出,因此found
最多只能打印一次。
在Unix和Linux上的类似线程上(什么都没找到时,make find失败),如果什么也没找到,我曾经grep -qz
返回一个非零的退出状态find
:
find /some/path -print0 -quit | grep -qz .
您可以使用&&
或使用它来构造复合命令if
:
find /some/path -print0 -quit | grep -qz . && echo found
-print0 -quit
。在此之前放置的内容取决于要查找的内容。我选择在这里省略。
muru的答案很合适,非常适合我们想要在发现文件时进行打印的情况。对于通常要执行外部命令(例如)的情况echo
,可以使用-exec
flag。
$ find . -name 'xac' -exec echo "I found " {} \; -quit
I found ./xac
该{}
部分在-exec
和之间将文件名传递给命令\;
作为参数。注意\
前面的内容;
-它可以防止shell误解;在shell结束时,分号表示命令结束,但是当使用斜杠转义时,shell会将其视为要传递给find
command的文字文本,并在找到命令时将其用作关闭-exec
标志的参数。
为了构造这种条件if found do this; else do that
,我们可以使用命令替换$()
和test
命令(aka [
):
$ [ "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
解决丹的评论
丹在评论中问:
回显“我发现{}”会比回声“我发现{}”好吗?也许可以用echo很好,但是如果有人复制了该命令并用另一个命令替换了echo,他们可能会遇到问题
让我们首先了解问题。通常,在shell中有单词拆分的概念,这意味着未引号的变量和位置参数将被扩展并视为单独的项。例如,如果您有变量var
并且它包含hello world
文本,那么当您执行touch $var
此操作时,shell会将其分解为两个单独的项目hello
,world
并且touch
将理解为好像您试图创建2个单独的文件一样;如果您这样做touch "$var"
,则shell将被hello world
视为一个单位,并且touch
只会创建一个文件。重要的是要了解,这仅是由于Shell的工作方式而发生。
相比之下,find
它不会遭受此类行为的困扰,因为命令由命令find
本身处理并由execvp()
系统调用执行,因此不涉及任何外壳程序。尽管花括号在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的问题-外壳会进行单词拆分。
$ 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中引用时,它将起作用。但同样,这对shell很重要,而不是find
。
$ find -type f -exec bash -c "stat -c '%F' '{}'" sh \;
regular empty file
regular empty file
regular empty file
echo "I found {}"
比echo "I found " {}
?也许对echo没问题,但是如果有人复制命令并用另一个命令替换echo,他们可能会遇到问题。
/some/path
告诉找到从哪里开始寻找,但没有告诉它寻找什么。在您的链接答案中也是如此。对我有用的是find /some/path -name xac -print0 -quit | grep -qz . && echo found
。我错过了什么?