分裂

分裂

我想将 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

上面的例子实现了splitjoin并行处理多个管道。split是“单输入,多输出”,join是“多输入,单输出”。

在 shell/bash 脚本中实现演示的最佳方法是什么splitjoin

答案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,或者在这种情况下可能更好地使用awkperl等等。

或者变得古怪...

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.

相关内容