Rut*_*art 6 shell grep text-processing
如果缺少值,我想在文本文件中插入新行。例如,我有以下文本文件 (A.txt),缺少第 5 行。此外,由于文件应该有 12 行,因此第 11-12 行也丢失了。
1 2.30
2 3.01
3 3.22
4 3.34
6 3.01
7 2.90
8 2.99
9 3.00
10 3.02
Run Code Online (Sandbox Code Playgroud)
我的预期输出如下。对于缺失的情况,应添加一行,其中包含编号和 NA。如您所见,这在第 5、11 和 12 行按预期发生:
1 2.30
2 3.01
3 3.22
4 3.34
5 NA
6 3.01
7 2.90
8 2.99
9 3.00
10 3.02
11 NA
12 NA
Run Code Online (Sandbox Code Playgroud)
我可以通过使用以下脚本来做到这一点:
f1=/my-directory/
echo "new file" > "$f1"/newfile.txt
for i in {1..12}; do
l=$(awk '{print $1}' /"$f1"/A.txt | grep -wE ^$i /"$f1"/A.txt)
if grep --quiet -wE ^$i /"$f1"/A.txt; then echo "$l" >> "$f1"/newfile.txt; else echo "$i NA" >> "$f1"/newfile.txt; fi
done
Run Code Online (Sandbox Code Playgroud)
这工作正常。然而,问题是我需要对包含超过 160000 行的大约 600 个文件执行此操作。因此,循环解决方案将花费太多时间搜索所有行。我的问题是:有没有更简单的解决方案可以做到这一点?
join 在这里运行良好:
join -a 1 -o 0,2.2 -e NA <(seq 12) A.txt 2>/dev/null
Run Code Online (Sandbox Code Playgroud)
我扔掉标准错误,因为join如果连接字段没有按词法排序,我会抱怨。
您可以使用awk脚本来执行此操作:
awk '{ while (NR + shift < $1) { print (NR + shift) " NA"; shift++ }; print } END { shift++; while (NR + shift < 13) { print (NR + shift) " NA"; shift++ } }' /tmp/test1
Run Code Online (Sandbox Code Playgroud)
将产生所需的输出/tmp/test1(将其替换为您要处理的每个文件)。
以更易读的形式:
#!/usr/bin/awk -f
{
while (NR + shift < $1) {
print (NR + shift) " NA"
shift++
}
print
}
END {
shift++
while (NR + shift < 13) {
print (NR + shift) " NA"
shift++
}
}
Run Code Online (Sandbox Code Playgroud)
将其保存为文件,例如fill-missing,使其可执行,然后您可以简单地运行
./fill-missing /tmp/test1
Run Code Online (Sandbox Code Playgroud)
该脚本处理每一行,并跟踪 中当前行号的预期增量shift。因此,对于每一行,如果当前调整的行与该行中的第一个数字不匹配,它将打印适当的行号,然后NA增加增量;一旦行号匹配,它就会打印当前行。在该过程结束时,它会打印达到 12 所需的所有缺失行。