插入带有缺失值的新行 (NA)

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 个文件执行此操作。因此,循环解决方案将花费太多时间搜索所有行。我的问题是:有没有更简单的解决方案可以做到这一点?

gle*_*man 5

join 在这里运行良好:

join -a 1 -o 0,2.2 -e NA  <(seq 12)  A.txt  2>/dev/null
Run Code Online (Sandbox Code Playgroud)

我扔掉标准错误,因为join如果连接字段没有按词法排序,我会抱怨。


Ste*_*itt 3

您可以使用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 所需的所有缺失行。