首页 > 解决方案 > 如何使用 GNU 并行处理 'read word1 word2' 的等价物

问题描述

我有一个管道,它给了我两行带引号的空格分隔的字符串。使用 echo 给你一个管道内容的例子:

echo -e "\"filename1\" \"some text 1\"\n\"filename2\" \"some text 2\""

"filename1" "some text 1"
"filename2" "some text 2"

第一个字符串是文件名,第二个是我要附加到该文件的文本。使用“read”获取 $filename 和 $text 的句柄很容易:

echo -e "\"filename1\" \"some text 1\"\n\"filename2\" \"some text 2\""|
while read filename text; do echo $text $filename; done

"some text 1" "filename1"
"some text 2" "filename2"

但是“parallel”并不想把线上的两个字符串当作两个参数。似乎将他们视为一体。

echo -e "\"filename1\" \"some text 1\"\n\"filename2\" \"some text 2\""|
parallel echo {2} {1}

"filename1" "some text 1"
"filename2" "some text 2"

所以只要有 {1} 就可以得到相同的结果

echo -e "\"filename1\" \"some text 1\"\n\"filename2\" \"some text 2\""|
parallel echo {1}

"filename1" "some text 1"
"filename2" "some text 2"

添加--colsep ' '使它打破每个空间的字符串

echo -e "\"filename1\" \"some text 1\"\n\"filename2\" \"some text 2\""|
parallel --colsep ' ' echo {2} {1}

"some "filename1"
"some "filename2"

我只是在其文档https://www.gnu.org/software/parallel/man.html中找不到有关如何通过管道并行处理此案例的解释

添加一个--delimiter ' '选项给出了这个

echo -e "\"filename1\" \"some text 1\"\n\"filename2\" \"some text 2\""| 
parallel --delimiter ' ' echo {2} {1}

"filename1"
"some
text
1"
"filename2"
"some
text
2"

这是我找到的最接近的

seq 10 | parallel -N2 echo seq:\$PARALLEL_SEQ arg1:{1} arg2:{2}

seq:1 arg1:1 arg2:2
seq:2 arg1:3 arg2:4
seq:3 arg1:5 arg2:6
seq:4 arg1:7 arg2:8
seq:5 arg1:9 arg2:10

但它并没有真正反映我的数据,因为seq 10每个字符串后面都有一个新行,而且我有两个字符串。

1
2
3
4
5
6
7
8
9
10

我目前的解决方法是将管道更改为使用逗号而不是空格来分隔一行中的引用字符串:

echo -e "\"filename1\",\"some text 1\"\n\"filename2\",\"some text 2\""|
parallel --colsep ',' echo {2} {1}

"some text 1" "filename1"
"some text 2" "filename2"

但是如何并行处理呢?

标签: bashgnu-parallel

解决方案


如果您对去除引号感到满意,那么--csv与之配对的选项--colsep将拆分到您想要的位置(并且仍然正确保留所有空格)

echo -e "\"filename1\" \"some text 1\"\n\"filename2 withspaces\" \"some text   2\""|
parallel --csv --colsep=' ' echo arg1:{1} arg2:{2}

输出:

arg1:filename1 arg2:some text 1
arg1:filename2 withspaces arg2:some text   2

注意--csv需要安装 perlText::CSV模块 ( sudo cpan Text::CSV)

如果你想保留引号,混合-q和一些额外的引号会将它们添加回来:

echo -e "\"filename1\" \"some text 1\"\n\"filename2 withspaces\" \"some text   2\""|
parallel -q --csv --colsep=' ' echo 'arg1:"{1}" arg2:"{2}"'

输出:

arg1:"filename1" arg2:"some text 1"
arg1:"filename2 withspaces" arg2:"some text   2"

--csv仅在最新版本的并行中(自 2018-04-22 起)。如果您年龄较大parallel,最好先通过预处理步骤将输入转换为并行可以处理的格式。我能看到的唯一方法是对 shell 引用和内部parallel处理进行真正的 hacky 开发:parallel

echo -e "\"filename1\" \"some text 1\"\n\"filename2 with spaces\" \"some text    2\""|
parallel sh -c "'echo arg1:\"\$1\" arg2:\"\$2\"'" echo '{= $Global::noquote = 1 =}'

输出:

arg1:filename1 arg2:some text 1
arg1:filename2 with spaces arg2:some text    2

这是如何工作的,我将作为练习留下......运行parallel --shellquote将显示它在引擎盖下构建的命令。


推荐阅读