查找命令后使用连接器


10

我希望我的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:


18

您可以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

我不得不凝视这一段时间。 /some/path告诉找到从哪里开始寻找,但没有告诉它寻找什么。在您的链接答案中也是如此。对我有用的是find /some/path -name xac -print0 -quit | grep -qz . && echo found。我错过了什么?

@Joe这里重要的是-print0 -quit。在此之前放置的内容取决于要查找的内容。我选择在这里省略。
muru

13

muru的答案很合适,非常适合我们想要在发现文件时进行打印的情况。对于通常要执行外部命令(例如)的情况echo,可以使用-execflag。

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

{}部分在-exec和之间将文件名传递给命令\;作为参数。注意\前面的内容;-它可以防止shell误解;在shell结束时,分号表示命令结束,但是当使用斜杠转义时,shell会将其视为要传递给findcommand的文字文本,并在找到命令时将其用作关闭-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会将其分解为两个单独的项目helloworld并且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,他们可能会遇到问题。

@Dan话题太长,无法在评论中讨论,因此我对答案进行了编辑。请看到它
谢尔盖Kolodyazhnyy

1
感谢您最终使我理解了为什么需要在该分号之前添加该分号。另外,对引用的解释也很棒。

1
没想到会有这么多细节可以回复我的评论。我非常感谢您的解释,谢谢!
丹·丹
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.