如果缺少值,我想在文本文件中插入新行。例如,我有以下文本文件 (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
我的预期输出如下。对于缺失的情况,应添加一行并注明编号和 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
我可以使用以下脚本来做到这一点:
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
这很好用。但问题是我需要对包含超过 160000 行的大约 600 个文件执行此操作。因此,循环解决方案将花费太多时间搜索所有行。我的问题是:是否有更简单的解决方案可以做到这一点?
答案1
join
在这里效果很好:
join -a 1 -o 0,2.2 -e NA <(seq 12) A.txt 2>/dev/null
我扔掉了 stderr,因为join
如果连接字段不是,则会抱怨从词汇上来说已排序。
答案2
您可以使用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
将产生所需的输出/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++
}
}
将其保存为文件,例如fill-missing
,使其可执行,然后您可以简单地运行
./fill-missing /tmp/test1
该脚本处理每一行,并跟踪 中当前行号的预期增量shift
。因此,对于每一行,如果当前调整的行与该行中的第一个数字不匹配,它将打印适当的行号,然后NA
增加增量;一旦行号匹配,它就会打印当前行。在该过程结束时,它会打印达到 12 所需的所有缺失行。
答案3
awk 文件
BEGIN { i=1 ; }
function upto(x) { while (i<x) printf "%d NA\n",i++ ;}
{ if ( $1 == i ) print ; upto($1) ; i++ ;}
END { upto(final+1) ;}
被称为与
awk -f nl.awk -v final=12 /tmp/test1
你的整个循环
cd /my/directory
ls | while read f
do
awk -f ~/nl.awk -v final=12 $f > /an/other/dir/$f
done
在哪里
- 你把 awk 程序放在你的 $HOME 目录中 (
~/nl.awk
)
答案4
Glenn Jackman 的bash
方法join
进行了一些调整,该函数从输入文件中获取计数,并使用该计数作为默认值:
# Usage: inlwmv file [ missing_value [ extra_lines ] ]
# if unset, missing_value="NA", and extra_lines=0
inlwmv() { join -a 1 -o 0,2.2 -e "${2:-NA}" \
<(seq $((${3:-0} + $(tail -n 1 "$1" | cut -d ' ' -f1))) | sort -k 1b,1) \
<(sort -k 1b,1 "$1") | \
sort -g ; }
对于OP问题:
inlwmv A.file "" 2
为了这个重复的问题Jackman 版本在最后一个值上失败一份文件,(join
对于排序非常挑剔,但使用sort
三次可以使其按要求运行):
inlwmv afile 0