好的,我会重新更新
我有2个文件--File1.txt,File2.txt
File1是基本模板
File2具有状态结果
N1,N2,N3,N4,N5,N6
XX,ZZ,XC,EE,RR,BB
XC,CF,FG,RG,GH,GH
DF,GH,MH,FR,FG,GH,NA
XX,ZZ,XC,EE,RR,BB,OK
下面的命令会比较两个文件中的第1列(如果匹配),然后从file2中的第7个单元格中检索该值,并将file1.txt作为最后一列附加到新标题中。
如果没有找到NA则更新。
使用的命令:
awk -F '
FNR==NR { a[$1]=$7; next }
FNR==1 { print $0; len=length($0); next }
{
printf $0
cont=(($1 in a) ? ","a[$1] : ",NA")
for ( i=length($0)+1; i<=len-length(cont); i++)
printf " "
print cont
}
' file2.txt file1.txt > tmp &&
第1天 - 在命令
之后运行N1,N2,N3,N4,N5,N6,D1
XX,ZZ,XC,EE,RR,BB,OK
XC,CF,FG,RG,GH,GH,NA
第2天 - 在命令
之后运行N1,N2,N3,N4,N5,N6,D1,D2
XX,ZZ,XC,EE,RR,BB,OK,OK
XC,CF,FG,RG,GH,GH,NA,NA
在第3天,我在File1底部插入了一个新行
N1,N2,N3,N4,N5,N6,D1,D2
XX,ZZ,XC,EE,RR,BB,OK,OK
XC,CF,FG,RG,GH,GH,NA,NA
DM,LC,VF,GR,GH,ES
现在当我在Day3上运行命令时,我需要像这样的输出
N1,N2,N3,N4,N5,N6,D1,D2,D3
XX,ZZ,XC,EE,RR,BB,OK,OK,OK
XC,CF,FG,RG,GH,GH,NA,NA,NA
DM,LC,VF,GR,GH,ES,,,NA
答案 0 :(得分:1)
这个awk
脚本似乎可以完成这项任务:
awk -F, '
BEGIN { OFS = FS }
FNR==NR { a[$1] = $7; next }
FNR==1 { n1 = n = NF + 1; $n = "D" (n-6); print; next }
{ $n1 = ($1 in a) ? a[$1] : "NA"; print }
' file2.txt file1.txt
OFS是输出字段分隔符; FS是(输入)字段分隔符。两者都通过,
选项设置为-F
,FS,通过赋值设置为OFS。这样可以轻松获得输出中正确数量的字段。 awk
没有运算符的字符串连接,以"D" (n-6)
为例,有点奇怪;你已经习惯了它,直到某一点,但它仍然看起来有点奇怪。
示例运行使用具有概要的程序ow
:
ow file cmd …args…
它通过cmd …args…
写入临时文件来保留文件的内容,如果命令成功(退出状态0)并且输出不为空,则它会保留原始文件的副本,忽略许多信号,然后将临时输出复制到原始信号上并清理。它非常有用 - 底部的代码。这就是我测试的方式。显然,我可以使用tmp=$(mktemp tmp.XXXXXX); awk … file1.txt > $tmp; mv $tmp file1.txt
代替,或者沿着那些方向使用。但是,由于我有ow
,我使用它。
$ cat file1.txt
N1,N2,N3,N4,N5,N6
XX,ZZ,XC,EE,RR,BB
XC,CF,FG,RG,GH,GH
$ ow file1.txt awk -F, '
> BEGIN { OFS = FS }
> FNR==NR { a[$1] = $7; next }
> FNR==1 { n1 = n = NF + 1; $n = "D" (n-6); print; next }
> { $n1 = ($1 in a) ? a[$1] : "NA"; print }
> ' file2.txt file1.txt
$ cat file1.txt
N1,N2,N3,N4,N5,N6,D1
XX,ZZ,XC,EE,RR,BB,OK
XC,CF,FG,RG,GH,GH,NA
$ ow file1.txt awk -F, '
> BEGIN { OFS = FS }
> FNR==NR { a[$1] = $7; next }
> FNR==1 { n1 = n = NF + 1; $n = "D" (n-6); print; next }
> { $n1 = ($1 in a) ? a[$1] : "NA"; print }
> ' file2.txt file1.txt
$ cat file1.txt
N1,N2,N3,N4,N5,N6,D1,D2
XX,ZZ,XC,EE,RR,BB,OK,OK
XC,CF,FG,RG,GH,GH,NA,NA
$ echo DM,LC,VF,GR,GH,ES >> file1.txt
$ ow file1.txt awk -F, '
> BEGIN { OFS = FS }
> FNR==NR { a[$1] = $7; next }
> FNR==1 { n1 = n = NF + 1; $n = "D" (n-6); print; next }
> { $n1 = ($1 in a) ? a[$1] : "NA"; print }
> ' file2.txt file1.txt
$ cat file1.txt
N1,N2,N3,N4,N5,N6,D1,D2,D3
XX,ZZ,XC,EE,RR,BB,OK,OK,OK
XC,CF,FG,RG,GH,GH,NA,NA,NA
DM,LC,VF,GR,GH,ES,,,NA
$
请注意,当您分配给$i
且i
大于NF时,NF会增加,并且所有丢失的字段都会创建为空字段。
此脚本的第一个工作版本具有更复杂的逻辑,循环创建空字段,但由于awk
将自动执行此操作,因此脚本大大简化。您经常会发现,通过一些时间和关注,可以简化和清理初始解决方案。
然而,指出这段代码非常信任可能也是相关的。它不能确保file2.txt
中恰好有7个字段。它不会检查file1.txt
中的每一行是否与文件中的第一行具有相同数量的字段,或者恰好是6个字段。如果您提供了棘手的数据,那么您将获得棘手的数据 - 历史悠久的GIGO原则:Garbage In, Garbage Out。
ow
: "@(#)$Id: ow.sh,v 1.6 2005/06/30 18:14:08 jleffler Exp $"
#
# Overwrite file
# From: The UNIX Programming Environment by Kernighan and Pike
# Amended: remove PATH setting; handle file names with blanks.
case $# in
0|1) echo "Usage: $0 file command [arguments]" 1>&2
exit 1;;
esac
file="$1"
shift
new=${TMPDIR:-/tmp}/ovrwr.$$.1
old=${TMPDIR:-/tmp}/ovrwr.$$.2
trap "rm -f '$new' '$old' ; exit 1" 0 1 2 15
if "$@" >"$new"
then
cp "$file" "$old"
trap "" 1 2 15
cp "$new" "$file"
rm -f "$new" "$old"
trap 0
exit 0
else
echo "$0: $1 failed - $file unchanged" 1>&2
rm -f "$new" "$old"
trap 0
exit 1
fi
awk
是否可以在标题中打印日期而不是 D1 ?
如果您想添加当前日期,则有两个主要选项。一,使用GNU gawk(通常也安装为awk),然后time functions使其变得简单。如果失败,awk -v date=$(date +'%Y-%m-%d') -F, …
将系统命令日期格式设为值,并将其作为变量日期传递给awk脚本,然后您可以将其打印到所需的位置。如果您希望传入任意日期,则第二种机制是要使用的机制。
awk -F, -v date=$(date +'%Y-%m-%d') '
BEGIN { OFS = FS }
FNR==NR { a[$1] = $7; next }
FNR==1 { n1 = n = NF + 1; $n = date; print; next }
{ $n1 = ($1 in a) ? a[$1] : "NA"; print }
' file2.txt file1.txt
这迫使今天的日期进入命令。您也可以前瞻性或回顾性地做事,例如:
tmp=$(mktemp coladd.XXXXXXXXX)
trap "rm -f $tmp; exit 1" 0 1 2 3 13 15
for dd in $(seq 1 31)
do
awk -F, -v date="2014-12-$dd" '
BEGIN { OFS = FS }
FNR==NR { a[$1] = $7; next }
FNR==1 { n1 = n = NF + 1; $n = date; print; next }
{ $n1 = ($1 in a) ? a[$1] : "NA"; print }
' file2.txt file1.txt > $tmp
mv $tmp file1.txt
done
鉴于这种额外的灵活性,我建议使用外部定义的日期而不是GNU的内部日期操作函数,但是YMMV。