我们知道sed命令循环遍历文件的每一行,并且对于每一行,它循环遍历给定的命令列表并执行某些操作。但是当文件非常大时,重复操作的时间和资源成本可能很糟糕。
假设我有一个行号的数组,我想用它作为地址来删除或使用sed命令打印(例如A=(20000 30000 50000 90000)
),并且有一个非常大的目标文件。
最简单的方法可能是:(注释@ John1024,注意每个循环的行号更改)
( for NL in ${A[@]}; do sed "$NL d" $very_large_file; done; )>.temp_file;
cp .temp_file $very_large_file; rm .temp_file
上面代码的问题是,对于数组的每个索引行号,它需要遍历整个文件。
为避免这种情况,我们可以:
#COMM=`echo "${A[@]}" | sed 's/\s/d;/g;s/$/d'`;
#sed -i "$COMM" $very_large_file;
#Edited: Better with direct parameter expansion:
sed -i "${A[@]/%/d;}" $very_large_file;
它首先打印数组并用d
的sed
命令替换它的SPACE和END_OF_LINE,这样字符串就像"20000d;30000d;50000d;90000d"
;在第二行,我们将此字符串视为sed
的命令列表。结果是,使用此代码,它只会循环遍历文件一次。
更重要的是,对于就地操作(论证-i
),即使感兴趣的最大行数已经过去,也不能使用q
与sed
一起退出,因为如果是这样,那行之后的行(例如90001+)将消失(It似乎就地操作只是用stdout覆盖文件)。
好主意?
(回复@user unknown :)我认为如果我们设法在所有索引行都通过后“退出”循环,它可能会更有效率。出于上述原因,我们不能使用sed -i
。将每行打印到文件比复制文件花费更多的时间(例如cat file1 > file2
和cp file1 file2
)。我们可以使用任何其他方法或工具从这个概念中受益。这就是我的期望。
PS:这个问题的要点是“线路位置”和“效率”; “删除行”操作只是一个例子。对于实际任务,还有更多 - 附加/插入/替换,字段分离,案例判断,然后读取/写入文件,计算等。顺序说,它可以调用所有类型的操作,创建子shell或不关心变量传递,...所以,使用的工具应该允许我进行行处理,问题是如何让自己进入感兴趣的行,进行各种操作。
任何评论都表示赞赏。
sed用于执行s / old / new,这就是全部,当你为混音添加一个shell循环时,你真的已经离开了轨道(参见https://unix.stackexchange.com/q/169716/133219)。删除数字存储在数组中的行是(使用seq
生成输入,因为问题中没有提供样本输入/输出):
$ a=( 3 7 8 )
$ seq 10 |
awk -v a="${a[*]}" 'BEGIN{split(a,tmp); for (i in tmp) nrs[tmp[i]]} !(NR in nrs)'
1
2
4
5
6
9
10
如果你想在删除最后一个目标行后停止使用awk进行处理并让尾部完成作业,那么你可以预先计算出阵列中的最大值,然后直到最后一个目标行的部分做awk :
max=$( printf '%s\n' "${a[@]}" | sort -rn | head -1 )
head -"$max" file | awk '...' file > out
tail +"$((max+1))" file >> out
idk如果真的比让awk处理整个文件更快,因为awk非常有效,特别是当你没有引用任何字段时所以它不会进行任何字段拆分,但你可以尝试一下。
首先复制到文本文件以检查结果。您想要排序第一个最高的行号。
echo "${a[@]}" | sed 's/\s/\n/g' | sort -rn
你可以使用ed
将命令输入printf
:
printf "%s\n" "command1" "command2" w q testfile | ed -s testfile
结合这些
printf "%s\n" $(echo "${a[@]}" | sed 's/\s/\n/g' | sort -rn | sed 's/$/d/') w q |
ed -s testfile
编辑(tx @Ed_Morton): 这可以用更少的步骤编写
printf "%s\n" $(printf '%sd\n' "${a[@]}" | sort -rn ) w q | ed -s testfile
我无法删除sort
,因为每条删除指令都是从1开始计算亚麻布数。
我试图找到一个编辑文件的命令,而不重定向到另一个,但我开始说你应该复制。我别无选择,我必须赞成直接的awk
解决方案,不需要sort
。
您可以从您的行生成中间sed命令文件。
echo ${A[@]} | sort -n > lines_to_delete
min=`head -1` lines_to_delete
max=`head -1` lines_to_delete
# skip to first and from last line, delete the others
sed -i -e 1d -e ${linecount}d -e 's#$#d#' lines_to_delete
head -${min} input > output
sed -f lines_to_delete input >> output
tail -${max} input >> output
mv output input