因此我没有睡觉。 Sundeep 指出的这个R 命令真的很酷,但实现起来有点令人沮丧。所以我在 sed 的文档中挖掘了一下,发现了这个 first~step
first~step
Match every step'th line starting with line first. For example, ``sed -n 1~2p'' will print all the odd-numbered lines in the input stream,
and the address 2~5 will match every fifth line, starting with the second. first can be zero; in this case, sed operates as if it were equal
to step. (This is an extension.)
我已经试过了
sed '1~3R headers' lines
但结果不如预期
line1.1
header1
line1.2
line1.3
line2.1
header2
line2.2
line2.3
line3.1
header3
line3.2
因为R 正在追加行,所以可以通过在行文件中添加额外的第一行来避免这种情况
sed -i '1s/^/\n/' lines
比我们处理文件
sed '1~3R headers' lines > output
并从输出中删除这个额外的行
sed -i '1d' output
但是这种添加删除线的必要性也有点令人沮丧。
有没有更好的办法?
我想知道 grep 是否足够快?可以试试吗?
headers=( $(cat headers) )
for header in ${headers[@]}; {
echo $header >> output
digit=${header//[!0-9]/}
grep .*$digit. lines >> output
}
好的,哪种方法更快?我已经用这个制作了测试文件
for i in {1..100}; { echo "header$i" >> headers; }
for i in {1..100}; { for e in {1..3}; { echo "line$i.$e" >> lines;}; }
100 和 300 行,并测试所有方法
paste -d '\n' headers - - - <lines
real 0m0,003s
user 0m0,000s
sys 0m0,003s
sed -e 'R lines' -e 'R lines' -e 'R lines' headers
real 0m0,003s
user 0m0,000s
sys 0m0,003s
awk -v r=3 '1;{for(i=1;i<=r;++i) {getline < "-"; print}}' headers <lines
awk -v r=3 '(NR==FNR){b[FNR]=$0;next}(FNR%r==1){print b[++c]}1' headers lines
real 0m0,005s
user 0m0,000s
sys 0m0,005s
这些都是明显的赢家。这也很快但不正确。
$ time awk 'NR==FNR{hdrs[NR]=$0; next} NR%3 == 1{print hdrs[++c]} 1' headers lines | head -n7
line1.1
line1.2
header1
line1.3
line2.1
line2.2
header2
real 0m0,004s
user 0m0,002s
sys 0m0,003s
好的,这就是 TS 使用的。
fun1 () {
new_reads_no="$(wc -l headers | awk '{print $1}')"
sequence="$(seq 1 $new_reads_no)"
for i in $sequence
do
start=$((3*($i-1)+1))
end=$(($start+2))
awk -v c1=$i 'FNR==c1' headers
awk -v s="$start" -v e="$end" 'NR>=s&&NR<=e' lines
done
}
real 0m0,341s
user 0m0,219s
sys 0m0,132s
嗯,这根本不快)
fun2 () {
headers=( $(cat headers) )
for header in ${headers[@]}; {
echo $header
digit=${header//[!0-9]/}
grep .*$digit. lines
}
}
real 0m0,167s
user 0m0,105s
sys 0m0,068s
我的也失败了,但仍然比第一个更快)
所以我在这里得到了真正需要的东西并做了这个。
fun3 () {
exec 3< headers
exec 4< lines
while read -u3 head do;
echo $head
for i in {1..3}; {
read -u4 line; echo $line
}
done
exec 3<&-
exec 4<&-
}
real 0m0,009s
user 0m0,009s
sys 0m0,000s
而且速度很快)
import sys
with open(sys.argv[1]) as small, open(sys.argv[2]) as large:
for line in small:
print(line, end='')
for x in range(3):
print(large.readline(), end='')
real 0m0,021s
user 0m0,016s
sys 0m0,004s
Python 也不错。
而且这两个也不错。
fun4 () {
while IFS= read -r; do
# Map 3 lines of big_file.txt without capturing newline character
mapfile -t -n 3 -u 3
# Output header $REPLY from small_file.txt
# followed by ${MAPFILE[@]} mapped lines of big_file.txt
printf '%s\n%s' "$REPLY" "${MAPFILE[@]}"
done <lines 3<headers
}
real 0m0,017s
user 0m0,012s
sys 0m0,004s
fun5 () {
while IFS= read -r; do
mapfile -t -n 3 -u 3 -C'echo "$REPLY";:' -c 3
printf '%s\n' "${MAPFILE[@]}"
done <headers 3<lines
}
real 0m0,011s
user 0m0,011s
sys 0m0,000s