我想将 1 个命令的输出通过管道传输到多个管道,并将多个命令的输出通过管道传输到 1 个命令。
例如split
:
# Single output to multiple pipes
echo "This is a sentence" | split | cut -d ' ' -f 1,3 > file1.txt
| cut -d ' ' -f 2,4 > file2.txt
在上面的例子中split
,输出"This is a sentence"
被分成 2 个cut
部分和 2 个不同的文件。
例如join
:
Hello(){
echo "Hello $1 and $2"
}
echo "Alice" |
echo "Bob" | join | Hello
# output: "Hello Alice and Bob"
在上面的例子中,从 2 个不同的管道获取输出并将它们作为 2 个管道输入join
提供给函数。Hello
split
和一起使用的示例join
:
# split the input into multiple pipes
echo "Alice Bob Charlie Dave" | split
# 2 separate split pipes are processed and then joined into a single pipe
split | cut -d ' ' -f 1,3 | join
split | cut -d ' ' -f 2,4 | join
Hello(){
echo "$1 loves $2"
}
join | Hello
# Output:
# Alice Charlie loves Bob Dave
上面的例子实现了split
和join
并行处理多个管道。split
是“单输入,多输出”,join
是“多输入,单输出”。
在 shell/bash 脚本中实现演示的最佳方法是什么split
?join
答案1
您可以使用 GNU Parallel 进行分割:
echo "This is a sentence" |
parallel --tee --pipe -q cut -d ' ' -f {} ::: 1,3 2,4
echo "This is a sentence" |
parallel --tee --pipe "cut -d ' ' -f {} >file{#}" ::: 1,3 2,4
答案2
另一种方法是使用tee
,或者在这种情况下可能更好地使用awk
,perl
等等。
或者变得古怪...
echo "Jane Bob Alice Joe" |
(tee >(
cut -d ' ' -f1,3 -z >&2 && printf ' loves ' >&2) |
cut -d ' ' -f2,4
) 2>&1 |
tr -d '\0'
简·爱丽丝喜欢鲍勃·乔
分裂
使用tee
+ 进程替换 / 子 shell 进行拆分。
echo "This is a sentence" |
tee >(cut -d ' ' -f1,3 >file1.txt) |
cut -d ' ' -f2,4 >file2.txt
# ...
echo "This is a sentence with some more words" |
tee \
>(cut -d ' ' -f1,3 >file1.txt) \
>(cut -d ' ' -f2,4 >file2.txt) \
>(cut -d ' ' -f3,5 >file3.txt) \
>(cut -d ...
但是例如awk
我们可以做更多逻辑同时还保持流程和解析。
awk '{
print $1,$3 > "file1.txt"
print $2,$4 > "file2.txt"
}'
# ... arbitrary length of input:
awk '{
for (i = 1; i < NF - 1; ++i)
print $i, $(i + 2) > sprintf("file%02d.txt", i)
}'
加入
至于join
目标到底是什么,目前还不太清楚。以下是一些变体:
从以下开始:
#! /bin/bash -
awk '{
for (i = 1; i < NF - 1; ++i)
print $i, $(i + 2) > sprintf("file%02d.txt", i)
}'
...或者简单来说
#! /bin/awk -f
{
for (i = 1; i < NF - 1; ++i)
print $i, $(i + 2) > sprintf("file%02d.txt", i)
}
$ ./splitinput <<<"Alice Jim Jane Carl An Fred Adler Morgan"
$ tail file0*
==> file01.txt <==
Alice Jane
==> file02.txt <==
Jim Carl
==> file03.txt <==
Jane An
==> file04.txt <==
Carl Fred
==> file05.txt <==
An Adler
==> file06.txt <==
Fred Morgan
- 使用
paste
:
$ paste -d ' ' file01.txt <(echo loves) file02.txt
Alice Jane loves Jim Carl
- 使用
bash
读取单次拍摄:
hello() {
printf '%s loves %s\n' "$1" "$2"
}
IFS= read -r name1<"$1"
IFS= read -r name2<"$2"
hello "$name1" "$name2"
./script file01.txt file02.txt
多组操作
bash
与 read 结合使用cat
:
names=()
while IFS= read -r name; do
names+=("$name")
done< <(cat $@)
# Which can be simplified as:
IFS=$'\n' read -rd '' -a names< <(cat file*)
给出要使用的名称数组:
printf '# Name: %s\n' "${names[@]}"
# Name: Alice Jane
# Name: Jim Carl
# Name: Jane An
# Name: Carl Fred
# Name: An Adler
# Name: Fred Morgan
printf ';; bash for\n'
for ((i = 0; i < ${#names[@]}; i += 2)) do
hello "${names[@]:i:i+2}"
done
使用循环处理所有文件read
:
printf ';; bash while argv\n'
while [ $# -gt 0 ]; do
IFS= read -r name1<"$1"
shift
IFS= read -r name2<"$1"
shift
hello "$name1" "$name2"
done
用于awk
处理所有文件:
printf ';; awk\n'
awk -v adv=loves '
{
if (NR % 2)
name=$0
else
print name,adv,$0
}' "$@"
Alice Jane loves Jim Carl
Jane An loves Carl Fred
An Adler loves Fred Morgan
或者,变得花哨起来。
hello2() {
fmt -uw32 <<-EOH
$1 loves $2, $2 loves $3 and $3 loves $2.
$5 is in love with $4 and $6 is all alone,
but has a secret crush on both $1 and $3.
EOH
}
hello2 "${names[@]}"
Alice Jane loves Jim Carl, Jim
Carl loves Jane An and Jane An
loves Jim Carl.
An Adler is in love with Carl
Fred and Fred Morgan is all
alone, but has a secret crush
on both Alice Jane and Jane An.