- 主题:GNU和BSD版本的xargs 分隔符不同
例子:
list="a b c d e"; echo $list |xargs -n1 -I{} echo begin {} end
在Mac上执行结果:
begin a end
begin b end
begin c end
begin d end
begin e end
在Linux上执行结果:
begin a b c d e end
我这里的需求是有一堆输入,要分别以其为参数,执行一些命令,无论是否成功都要对所
有目标执行,所以
1 “一些命令”我选用shell function来实现,在其中读了$1作为本次处理的目标
2 “所有目标”我选用xargs;如果选Parallel还得额外安装
结果发现xargs在切分“以空格为分隔符”的字符串的时候,GNU版本默认不切分,结果把
整个“含空格分隔符的字符串”传给函数,执行了一次,而函数里又选了$1作为本次执行
目标,其综合结果就是只对列表中第一个目标执行了一遍
更惨的是我对比的时候是在Mac上做的对比,怎么看怎么顺眼……
--
修改:JulyClyde FROM 222.71.112.*
FROM 222.71.112.*
比较奇怪的是,GNU xargs的manpage写的是:
This manual page documents the GNU version of xargs. xargs reads items from the standard input, delimited by blanks (which can be protected with double or single quotes or a backslash) or newlines
按说应该支持空格啊
【 在 JulyClyde 的大作中提到: 】
: 例子:
: list="a b c d e"; echo $list |xargs -n1 -I{} echo begin {} end
: 在Mac上执行结果:
: ...................
--
FROM 222.71.112.*
像是GNU xargs的bug
xargs.c的read_line函数里:
893 /* POSIX: In the POSIX locale, the separators are <SPC> and
894 * <TAB>, but not <FF> or <VT>.
895 */
896 if (!bc_ctl.replace_pat && ISBLANK (c))
897 {
898 *p++ = '\0';
899 len = p - linebuf;
900 if (EOF_STR (linebuf))
901 {
902 eof = true;
903 return first ? -1 : len;
904 }
905 bc_push_arg (&bc_ctl, &bc_state,
906 linebuf, len,
907 NULL, 0,
908 initial_args);
909 p = linebuf;
910 state = SPACE;
911 first = false;
912 continue;
913 }
这一段状态机代码应该是“之前读到了普通字符,这次读到了空格”的处理,这时候应该把已经读到的这一段作为一个参数加到列表里去
看它的判断条件if (!bc_ctl.replace_pat && ISBLANK (c))
其实是要求没用-i/-I参数,且本次读到的字符为空白
验证一下:
echo a b c d e |xargs -n1 -i{} echo begin {} end
命令的结果是原帖说的错误
begin a b c d e end
但是去掉-i之后
echo a b c d e |xargs -n1 echo begin {} end
运行结果就几乎正确了。虽然丧失了使用占位符的能力,但至少它确实按照空格进行分割了
begin {} end a
begin {} end b
begin {} end c
begin {} end d
begin {} end e
我觉得这个判断条件就是个bug
【 在 JulyClyde 的大作中提到: 】
: 比较奇怪的是,GNU xargs的manpage写的是:
: This manual page documents the GNU version of xargs. xargs reads items from the standard input, delimited by blanks (which can be protected with double or single quotes or a backslash) or newlines
: 按说应该支持空格啊
: ...................
--
FROM 222.71.112.*
这个看看?
https://unix.stackexchange.com/questions/428310/problem-using-xargs-max-args-replace-with-default-delimiter
{quote}
That behaviour (that newline should be the only delimiter with -I) is
documented in the GNU xargs documentation and the POSIX specification (under
XSI, so it's not surprising that OpenBSD doesn't comply there). In any case,
using -n with -I makes little sense as {} is to replace one argument anyway.
{quote}
$ printf "%s\n" a b c d e | xargs -I{} echo begin {} end
begin a end
begin b end
begin c end
begin d end
begin e end
【 在 JulyClyde 的大作中提到: 】
: 例子:
: list="a b c d e"; echo $list |xargs -n1 -I{} echo begin {} end
: 在Mac上执行结果:
: ...................
--
修改:haha103 FROM 182.150.115.*
FROM 182.150.115.*
我不是说非要用printf来怎么样,我是说这个link里面说GNU xargs/POSIX的文档说明了这个问题。。。(是一个已知问题,甚至是一个feature,不是问题)
-I replstr
[XSI] [Option Start] Insert mode: utility is executed for each logical line
from standard input. Arguments in the standard input shall be separated only
by unescaped <newline> characters, not by <blank> characters. Any unquoted
unescaped <blank> characters at the beginning of each line shall be ignored.
The resulting argument shall be inserted in arguments in place of each
occurrence of replstr. At least five arguments in arguments can each contain
one or more instances of replstr. Each of these constructed arguments cannot
grow larger than an implementation-defined limit greater than or equal to 255
bytes. Option -x shall be forced on. [Option End]
【 在 JulyClyde 的大作中提到: 】
: xargs的stdin不太好控制
: 我这里其实是echo了一个array出来,就是用空格的
: 改printf不太方便吧
: ...................
--
修改:haha103 FROM 182.150.115.*
FROM 182.150.115.*
按这个文档的话,GNU的倒是符合标准
但是不满足需求啊
我原来想的是-I强制-n1(因为一个占位符只能替换成一个参数),但是不应该影响参数
解析的过程
没想到它居然强制使用“一整行”来作为一个参数
【 在 haha103 的大作中提到: 】
: 我不是说非要用printf来怎么样,我是说这个link里面说GNU xargs/POSIX的文档说明
: 了这个问题。。。(是一个已知问题,甚至是一个feature,不是问题)
: -I replstr
: [XSI] [Option Start] Insert mode: utility is executed for each logical line
: ...................
--
FROM 222.71.112.*
所以只有其他程序来迁就它了,毕竟标准就这么规定的 :)
【 在 JulyClyde 的大作中提到: 】
: 标 题: Re: GNU和BSD版本的xargs 分隔符不同
: 发信站: 水木社区 (Fri Jan 13 14:37:02 2023), 站内
:
: 按这个文档的话,GNU的倒是符合标准
: 但是不满足需求啊
:
: 我原来想的是-I强制-n1(因为一个占位符只能替换成一个参数),但是不应该影响参数
: 解析的过程
: 没想到它居然强制使用“一整行”来作为一个参数
: 【 在 haha103 的大作中提到: 】
: : 我不是说非要用printf来怎么样,我是说这个link里面说GNU xargs/POSIX的文档说明
: : 了这个问题。。。(是一个已知问题,甚至是一个feature,不是问题)
: : -I replstr
: : [XSI] [Option Start] Insert mode: utility is executed for each logical line
: : ...................
:
: --
:
: ※ 来源:·水木社区 mysmth.net·[FROM: 222.71.112.*]
--
FROM 182.150.115.*
呜呜呜呜
【 在 haha103 的大作中提到: 】
: 所以只有其他程序来迁就它了,毕竟标准就这么规定的 :)
--
FROM 222.71.112.*
我这里比较倒霉的是:
被xargs调用的,因为需要对一个参数执行多个命令,所以我写成一个shell function,然后export -f f使其在sub shell也可用
实际调用格式是
echo ${array[@]} | xargs -n1 -I{} bash -c 'f {}'
虽然{}是在最尾部,但必须和f一起作为bash -c的参数,这个函数才能接收到参数,否则就变成了
bash -c 'f' {}
相当于无参数调用
为了表达“函数f和它的参数一起”,我就必须使用-I占位符功能
然后就受到-n和-I冲突的问题影响了
按你的建议,我现在改成
printf '%s\n' ${array[@]} | xargs -I{} bash -c 'f {}'
【 在 haha103 的大作中提到: 】
: 所以只有其他程序来迁就它了,毕竟标准就这么规定的 :)
--
FROM 222.71.112.*