将结果传送到多个命令,无需在屏幕上书写

将结果传送到多个命令,无需在屏幕上书写

我有一个非常大的 zip 文件(~10 GB),我想解压它,结果必须传递给两个命令。两个后续命令的结果必须附加到文件中,并且

目前,我运行

unzip -p bigFile.zip | head -n 1 >> output.txt
unzip -p bigFile.zip | grep -v 'skipLine' >> output.txt

这给出了大约一百万行。现在,我想用 1 行来做。使用tee,我想出了

unzip -p bigFile.zip | tee >(head -n 1 >> output.txt) >(grep -v 'skipLine' 
>> output.txt)

但该output.txt文件仅包含 51 行,其中最后一行甚至不完整。另外,后一个命令将结果打印到终端,这是我不想要的。

我也尝试过

unzip -p bigFile.zip | tee >(head -n 1 >> output.txt) | grep -v 'skipLine' 
>> output.txt

但不幸的是,这也不起作用。

任何帮助是极大的赞赏!没有必要使用tee,任何其他命令都可以正常工作,只要我可以将部件的输出传递unzipheadgrep命令。

编辑:head如果和grep命令的输出可以“组合”然后传递给 ,那就更好了zip。这可能吗?

答案1

您可以解压并通过管道输入 shell 脚本,该脚本使用并打印第一行,并允许 grep 使用其余内容:

unzip -p bigFile.zip | {
    IFS= read -r header       # consume the first line, verbatim
    printf "%s\n" "$header"
    grep -v 'skipLine' 
} >> output.txt

从块打印的所有内容都将附加到输出文件中。

答案2

我想不出一种方法来通过管道传输两个单独的命令,但您可以使用awk

unzip -p file.zip | awk 'NR==1 || !/skipLine/' > output

NR==1如果当前行是第一行 ( ) 或不匹配skipline( !/skipLine),则 awk 命令将打印当前行。

我能想到的最好的组合grephead

unzip -p file.zip | tee >(head -n1 > output) | tail -n+2 | grep -v skipLine >> output

这个想法是首先捕获第一行head -n1,然后使用tail -n+2打印除第一行之外的所有内容,然后将其传递给grep.但只要使用该awk方法,它就更简单、更容易。

答案3

也许我错过了一个微妙的点,但看起来你想保留第一行,然后保留第一行之后不包含唯一文本的任何内容skipLine。看起来sed会很好地处理这个问题。

#!/bin/bash
sed -n '1 {p;d}         #for line 1, print and discard
        /skipLine/d     #delete any line with skipLine
        p               #print remainder
' << End_of_SampleData
head
prefix skipLine
keepLine
skipLine suffix
keepLine
End_of_SampleData

输出:

head
keepLine
keepLine

unzip -p bigFile.zip | sed ...如果此测试用例符合您的要求,您可以将数据通过管道传输到此脚本中。这应该很快,因为只有一个unzip和一个sed进程要运行。

答案4

您的命令遇到两个问题tee

tee >(head -n 1 >>output.txt) >(grep -v 'skipLine' >>output.txt)

最简单的一个是您想要丢弃输出。为此,您可以简单地将标准输出发送到 /dev/null:

tee >(head -n 1 >>output.txt) >(grep -v 'skipLine' >>output.txt) >/dev/null

但这似乎很浪费;将第二个命令连接到tee标准输出会更有效:

tee >(head -n 1 >>output.txt) | grep -v 'skipLine' >>output.txt

第二个是head在读取所需的输入后关闭其输入。简单的修复方法是使用一个丢弃其输入的过程:

tee >(head -n 1 >>output.txt; dd of=/dev/null) | grep -v skipLine >>output.txt

如果我们希望此管道替换任何先前的内容,我们可以将两个打开替换output.txt为一个打开:

exec 3>output.txt
tee >(head -n 1 >&3; dd of=/dev/null) | grep -v skipLine >&3

请注意,在所有这些版本中,不能保证标题行位于输出文件的开头,这与具有两个独立管道的初始版本不同。如果这是一个要求,那么请查看其他答案之一以进行替换(或者用sleep之前的任意序列进行赌博grep)。

但我希望这个答案对你有帮助理解为什么您会看到自己所做的结果,而不仅仅是填鸭式的替代方案。

相关内容