xargs 使用 -d'\n' 时忽略空行

Jac*_*ick 2 xargs

我有一个文件输入可能有空行,我想跳过任何空行。
我正在尝试找到一个不需要使用 grep / tr 并将输出通过管道传输到 xargs 的解决方案

我使用以下 xarg 选项

-r如果没有参数,我不希望运行该命令。 -d '\n'新行是分隔符。

使用回显命令:

echo "" | xargs -r -d'\n' -I {}  echo "test '{}'"
Run Code Online (Sandbox Code Playgroud)

输出:

test ''
Run Code Online (Sandbox Code Playgroud)

使用由空行组成的文件的命令:

xargs -a /tmp/test.txt -r -d'\n' -I {}  echo "test '{}'"
Run Code Online (Sandbox Code Playgroud)

输出:

test ''
test ''
test ''
Run Code Online (Sandbox Code Playgroud)

我可以如上所述使用 grep,但我想知道是否可以仅使用 xargs 来完成。

grep 示例(工作):

grep -v -e '^$' /tmp/test.txt | xargs -r -d'\n' -I {}  echo "test '{}'"
Run Code Online (Sandbox Code Playgroud)

Sté*_*las 8

-r-I不是忽略空元素,而是避免在输入没有元素时运行命令一次(尽管(也不是 BSD )不需要-J)。

您通常-r出于这个原因想要。

find . -criteria -print0 | xargs -0 ls -ld
Run Code Online (Sandbox Code Playgroud)

如果find没有找到任何东西,仍然会ls -d在没有参数的情况下运行,并且会列出..

所以你确实想要:

find . -criteria -print0 | xargs -r0 ls -ld
Run Code Online (Sandbox Code Playgroud)

如果什么也没找到,则ls根本不运行find

请注意, 和-r都是-0GNU 扩展(同样,-d可移植性更差)。-r是某些 BSD 的默认行为,xargs包括 FreeBSD 和 NetBSD(尽管这使得它们不符合 POSIX)。

(无论如何,xargs在该特定示例中不需要像您一样find . -criteria -exec ls -ld {} +)。

据我所知,GNUxargs是唯一支持选项的实现-d,并且它不支持过滤掉特定参数值,无论是空值还是其他值,因此使用grep(grep -v '^$'LC_ALL=C grep .) 是正确的方法。

如果您仍然想使用-a(另一个 GNU 扩展),例如为了让命令的 stdin 保持不变,并且使用支持 ksh 样式进程替换(ksh、zsh、bash)的 shell,您可以这样做:

xargs -rd '\n' -a <(grep -v '^$' test.txt) cmd --
Run Code Online (Sandbox Code Playgroud)
xargs -d '\n' -I{} -a <(grep -v '^$' test.txt) cmd -- {}
Run Code Online (Sandbox Code Playgroud)

(rc、akanga、es、fish 和 yash shell 具有相同的功能,但语法不同)。

注意-0是 like -d '\0',所以与 冲突-d '\n'。您必须选择d您想要的限制器。后者将优先,-0 -d '\n'因为它排在最后。

-0是首选分隔符,因为它是不能出现在命令参数或文件路径中的单字节值。,与现在在许多其他实现中发现的-0相反(包括大多数 BSD、Solaris、busybox、toybox、ast-open 的实现)。对于不支持的实现(即除 GNU 之外的所有实现),您可以使用:-dxargsxargs-dxargs

tr '\n' '\0' | xargs -0 ...
Run Code Online (Sandbox Code Playgroud)

代替 GNU 的:

xargs -d '\n' ...
Run Code Online (Sandbox Code Playgroud)

如果使用zsh,而不是使用xargs,您可以这样做:

for arg ( ${(f)"$(<test.txt)"} ) cmd -- $arg
Run Code Online (Sandbox Code Playgroud)

参数f扩展标志在换行符上拆分,并且由于${...}未加引号,所以空元素将被删除。

bash

readarray -t args < test.txt &&
  for arg in "${args[@]}"; do
    [ -z "$arg" ] || cmd -- "$arg"
  done
Run Code Online (Sandbox Code Playgroud)

您还可以通过不加引号的数组扩展来进行空删除,但是您还需要禁用通配符和拆分,这也是在未加引号的参数扩展时完成的:

IFS=; set -o noglob
readarray -t args < test.txt &&
  for arg in ${args[@]}; do
    cmd -- "$arg"
  done
Run Code Online (Sandbox Code Playgroud)

您还可以执行以下操作:

while IFS= read <&3 -r arg || [ -n "$arg" ]; do
  [ -z "$arg" ] || cmd -- "$arg" 3<&-
done 3< test.txt
Run Code Online (Sandbox Code Playgroud)

这是标准sh语法。