我有多个ascii输入数据文件,其中包含三列,如下所示:
File1中:
00005 3 a
00005 17 b
00007 20 c
00009 2 d
00042 4 e
00042 37 f
00090 49 g
文件2:
00005 3 A
00005 17 B
00009 2 C
00007 20 D
00042 4 E
00090 49 F
00042 37 G
文件3:
00005 3 100
00009 2 200
00007 20 300
00090 49 400
00042 37 500
前两列的作用类似于索引,第三列是数据属性。从我的示例文件中可以看出,前两列不必是任何顺序,某些文件中可能缺少某些索引。我想比较所有三个文件并输出如下:
输出1(合并数据):
00005 3 a A 100
00007 20 c D 300
00009 2 d C 200
00042 37 f G 500
00090 49 g F 400
输出2(数据不完整的指标):
00005 17
00042 4
我当前(和草率)的解决方案包括查找具有最多行的文件,从中获取索引,在其他文件中查找索引,以及打印这些:
我的解决方案:
cat file1 | while read line
do
index1=$(echo $line | awk '{print $1}')
index2=$(echo $line | awk '{print $2}')
attribute1=$(echo $line | awk '{print $3}')
attribute2=$(grep "^"$index1" "$index2" " file2 | awk '{print $3}')
attribute3=$(grep "^"$index1" "$index2" " file3 | awk '{print $3}')
echo $index1 $index2 $attribute1 $attribute2 $attribute3
done > output
然而,这会给我一个带有'holes'的输出文件,输出看起来像:
输出:
00005 3 a A 100
00005 17 b B
00007 20 c D 300
00009 2 d C 200
00042 4 e E
00042 37 f G 500
00090 49 g F 400
我仍然可以通过使用awk(分别为NF == 3和NF <3)找到好数据和缺失数据,但我觉得应该有一种更清洁(也可能更快)的方式我的解决方案很慢并容易出错(尤其是grep发现)。
答案 0 :(得分:0)
awk
救援!
如果你不能对文件进行排序,这里有一个解决方案
awk '{k=$1 FS $2}
FILENAME==ARGV[1] {a[k]=$3; next}
FILENAME==ARGV[2] {b[k]=$3; next}
{c[k]=$3}
(k in a) && (k in b) {print k,a[k],b[k],c[k] > "output1.txt"}
delete a[k]; delete b[k]; delete c[k]}
END {for(k in a) d[k];
for(k in b) d[k];
for(k in c) d[k];
for(k in d) print k > "output2.txt"}' file{1..3}
UPDATE 第一种解决方案并不总是最好的,代码重复太多而且不够通用。以下是更好的,但不一定更短。但可以扩展到更多的文件。
awk '{k=$1 FS $2}
{for(i=1;i<ARGC;i++)
if(FILENAME==ARGV[i])
{a[k,i]=$3; c[k]++}}
END {f="output1.txt";
for(k in c)
if(c[k]==ARGC-1)
{printf "%s", k > f;
for(i=1;i<=c[k];i++) printf "%s", OFS a[k,i] > f;
print "" > f}
else print k > "output2.txt"}' file{1..3}
答案 1 :(得分:0)
awk和bash都可以做到,但当然在讨论列时awk要容易得多:)
AWK:
#!/usr/bin/awk -f
{
arr[$1][$2] = arr[$1][$2] (arr[$1][$2]?" ":"") $3
}
END{
while(c++ < 2)
{
if( c == 1)
{
print "Combined values"
reg = /[0-9]$/
}
else
{
print "Incomplete values"
reg = /[A-Z]$/
}
for(i in arr)
for(j in arr[i])
if(arr[i][j] ~ reg)
print i,j,arr[i][j]
}
}
bash(4 +):
#!/usr/bin/env bash
declare -A arr
for file
do
while read -r i1 i2 v
do
arr[$i1$i2]="${arr[$i1$i2]}$([[ -n ${arr[$i1$i2]} ]] && echo -n " ")$v"
done<"$file"
done
for i in 1 2
do
if (( i == 1 ))
then
vals="Combined values"
reg='[0-9]$'
else
vals="Incomplete values"
reg='[A-Z]$'
fi
echo "$vals"
for idx in "${!arr[@]}"
do
[[ "${arr[$idx]}" =~ $reg ]] && echo "${idx:0:5} ${idx:5} ${arr[$idx]}"
done | column -t
done
您可以使用以下命令调用: - ./script_name files