Xargs

如何告訴xargs忽略空標準輸出?

  • March 15, 2022

如何更改此程式碼以免發出錯誤,換句話說,xargs如果 stdout 為空,則不執行程式碼。

終端:

$ cat << EOF > dummy.sh
#! /usr/bin/env bash
[[ -f "\$1" ]] &&  echo "file=\$1" || { echo "error"; exit 1; } 
shift 
(( \$# == 0 )) || "\$0" "\$@" 
EOF
$ chmod +x dummy.sh
$ mkdir trash.later && touch trash.later/foo
$ find trash.later -type f | xargs -n 1 ./dummy.sh 
file=trash.later/foo
$ find trash.later -type f | grep 'bar' | xargs -n 1 ./dummy.sh 
error

不要xargsfind. xargs預設情況下,期望輸入的參數以沒有命令輸出的格式分隔,當然不是find. 的輸出find -print也不能可靠地進行後處理。

find使用xargs可靠排序的唯一方法是使用-print0-0非標準擴展(最初來自 GNU find/ xargs,但現在在許多其他實現中都可以找到)。

如果輸入為空,GNUxargs也有一個-r/副檔名來不執行命令(某些實現,例如 NetBSD 上的預設實現)。--no-run-if-empty``xargs

所以在這裡,使用 GNU find//xargsgrep兼容的,你可以這樣做:

find trash.later -type f -print0 |
 grep -z bar |
 xargs -r -0 -n 1 ./dummy.sh

但這與標準相比沒有優勢:

find trash.later -path '*bar*' -type f -exec ./dummy.sh {} ';'

( where在文件路徑中-path '*bar*'查找任何地方,就像您嘗試做的那樣。替換為僅在文件名中查找(其路徑的最後一個組成部分))。bar``grep bar``-name '*bar*'``bar

為什麼循環查找的輸出是不好的做法?


作為對您問題的更一般的回答,對於xargs不支持-r/的實現,--no-run-if-empty解決方法是使用sh包裝器。

代替:

... | xargs -n1 cmd

做:

... | xargs sh -c 'for file do cmd "$file"; done' sh

sh如果沒有輸入,它仍然會執行,但由於參數列表是空的,循環中不會有通過,所以cmd不會執行。

另請參閱僅在輸入非空時執行命令的ifne命令moreutils

... | ifne xargs -n1 cmd

但是請注意,如果輸入不為空但僅包含空行,ifne則將執行xargsxargs仍會認為其輸入沒有參數並且仍然在cmd沒有參數的情況下執行一次(NetBSD 除外)。

為了完整性

... | xargs -I {} cmd {}

cmd如果輸入為空/空白,也不會執行。在這種情況下,將輸入拆分為參數是不同的:前導空格被刪除,引號仍然被處理(以xargs自己獨特的方式),但否則參數是整行而不是空格分隔的單詞。

引用自:https://unix.stackexchange.com/questions/694439