我有一个非常大的 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
,任何其他命令都可以正常工作,只要我可以将部件的输出传递unzip
给head
和grep
命令。
编辑: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 命令将打印当前行。
我能想到的最好的组合grep
是head
:
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
)。
但我希望这个答案对你有帮助理解为什么您会看到自己所做的结果,而不仅仅是填鸭式的替代方案。