- 主题: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.*
按这个文档的话,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.*
呜呜呜呜
【 在 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.*
之前我不知道用-d
我同事用了之后我才学到了
而且-d好像不清真?
【 在 stockbsd 的大作中提到: 】
: linux下 -d 参数不就可以吗?
: echo -n "a b c" | xargs -n1 -d' ' -i{} echo begin {} end
--
FROM 222.71.112.*