centos 如果stdin输入为空,如何忽略xargs命令?

mklgxw1f  于 2022-11-07  发布在  其他
关注(0)|答案(8)|浏览(145)

请考虑以下命令:

ls /mydir/*.txt | xargs chown root

其目的是将mydir中所有文本文件的所有者更改为root
问题是如果mydir中没有.txt文件,那么xargs会抛出一个错误,说明没有指定路径。这是一个无害的示例,因为会抛出一个错误,但在某些情况下,比如在我需要在这里使用的脚本中,则假定空路径为当前目录。因此,如果我从/home/tom/运行该命令,那么如果ls /mydir/*.txt没有结果,则/home/tom/下的所有文件的所有者都将更改为root。
那么,如何让xargs忽略空结果呢?

lnxxn5zx

lnxxn5zx1#

对于GNU xargs,您可以使用-r--no-run-if-empty选项:
--no-run-if-empty
-r
如果标准输入不包含任何非空白,则不要运行该命令。通常,即使没有输入,该命令也只运行一次。此选项是GNU扩展。
在macOS上使用的xargs的BSD版本不对空输入运行该命令,因此不需要-r选项(该版本的xargs也不接受该选项)。

l7wslrjt

l7wslrjt2#

非GNU xargs的用户可以利用-L <#lines>-n <#args>-i-I <string>

ls /empty_dir/ | xargs -n10 chown root # chown executed every 10 args or fewer
ls /empty_dir/ | xargs -L10 chown root # chown executed every 10 lines or fewer
ls /empty_dir/ | xargs -i cp {} {}.bak # every {} is replaced with the args from one input line
ls /empty_dir/ | xargs -I ARG cp ARG ARG.bak # like -i, with a user-specified placeholder

请记住,xargs在空格处分隔行,但可以使用引号和转义;有关详细信息,请参阅RTFM。
此外,正如Doron Behar所提到的,此解决方案不可移植,因此可能需要进行检查:
第一个

bbmckpt7

bbmckpt74#

对于xargs,您可以按照建议使用-r,但是BSD xargs不支持它。
因此,作为解决方法,您可以传递一些额外的临时文件,例如:

find /mydir -type f -name "*.txt" -print0 | xargs -0 chown root $(mktemp)

或将其stderr重定向为空(2> /dev/null),例如

find /mydir -type f -name "*.txt" -print0 | xargs -0 chown root 2> /dev/null || true

另一种更好的方法是使用while循环遍历找到的文件:

find /mydir -type f -name "*.txt" -print0 | while IFS= read -r -d '' file; do
  chown -v root "$file"
done

另请参阅:Ignore empty results for xargs in Mac OS X
另外请注意,您更改权限的方法并不好,不鼓励这样做。您绝对不应该解析ls command的输出(请参见:Why you shouldn't parse the output of ls)。特别是当你运行你的命令由根,因为你的文件可以包含特殊字符,可能会被解释的外壳或想象文件有一个空格字符周围的/,那么结果可能是可怕的。
因此,您应该改变方法,改用find命令,例如:

find /mydir -type f -name "*.txt" -execdir chown root {} ';'
fafcakar

fafcakar5#

使用-r/--no-run-if-empty xargs参数的跨平台(Mac和Linux)替代方法:
使用空参数的示例(在Ubuntu 18.04和Big Sur上的结果相同):

$ echo | xargs -I {}  echo "This is a test with '{}'"
$
$
$ cat /dev/null | xargs -I {}  echo "This is a test with '{}'"
$

具有多行的示例:

$ seq 1 5  | xargs -I {}  echo "This is a test with '{}'"
This is a test with '1'
This is a test with '2'
This is a test with '3'
This is a test with '4'
This is a test with '5'
$
zpjtge22

zpjtge226#

这是GNU xargs的一种行为,可以通过使用-r,--no-run-if-empty来抑制。
xargs的 *BSD变体在默认情况下有这种行为,所以不需要-r。从FreeBSD 7.1(2009年1月发布)开始,出于兼容性的原因,-r参数被接受(它什么也不做)。
我个人更喜欢在脚本中使用longopts,但由于 *BSD xargs不使用longopts,因此只需使用“-r”,xargs在 *BSD和linux系统上的作用相同
不幸的是,MacOS(目前是MacOS莫哈韦)上的xargs不支持“-r”参数。

kiayqfof

kiayqfof7#

在OSX上:Bash重新实现xargs处理-r参数,例如将其放入$HOME/bin并将其添加到PATH


# !/bin/bash

stdin=$(cat <&0)
if [[ $1 == "-r" ]] || [[ $1 == "--no-run-if-empty" ]]
then
    # shift the arguments to get rid of the "-r" that is not valid on OSX
    shift
    # wc -l return some whitespaces, let's get rid of them with tr
    linecount=$(echo $stdin | grep -v "^$" | wc -l | tr -d '[:space:]') 
    if [ "x$linecount" = "x0" ]
    then
      exit 0
    fi
fi

# grep returns an error code for no matching lines, so only activate error checks from here

set -e
set -o pipefail
echo $stdin | /usr/bin/xargs $@
44u64gxh

44u64gxh8#

删除以前的远程跟踪分支现在消失的所有本地引用


# !/bin/sh

LC_ALL=C git for-each-ref --format='%(refname:short) %(upstream:track)' refs/heads/ |\
    sed -n '/ \[gone\]$/{s@@@;p}' |\
    xargs -I% git branch --delete %
  1. LC_ALL=C,通过将语言设置为英语来避免本地化问题
    1.匹配以[gone]结尾的for-each-ref输出,并获取refname
    1.删除这些本地引用(将--delete更改为-D以强制执行)
    没有bashisms,应该在BSD/GNU中工作

相关问题