合并/排序不同的文件并将标题保留在顶部

合并/排序不同的文件并将标题保留在顶部

我有三组不同的文件,如下所示:

cat "110001_test file_first_file.csv"
ID,NAME,LOCATION
1,Vikrant,Gurgaon
2,Bharat,Noida
3,Raju,Hyderabad

cat "110001_test file_second_file.csv"
ID,NAME,LOCATION
1,Vikrant,Gurgaon
22,abcd,Noida
3,Raju,Hyderabad

cat "110001_test file_third_file.csv"
ID,NAME,LOCATION
1,Vikrant,Gurgaon
2,Bharat,Noida
33,xyz,Hyderabad

我使用下面的命令将这些文件合并在一起,并将标题保留在顶部一次,并删除重复项(如果有)。

find . -type f -name '*test file*.csv' -exec cat {} + | awk 'NR == 1; NR > 1 {print $0 | "sort -u"}' > output.file

它给我的输出为:

ID,NAME,LOCATION
1,Vikrant,Gurgaon
22,abcd,Noida
2,Bharat,Noida
33,xyz,Hyderabad
3,Raju,Hyderabad
ID,NAME,LOCATION

我了解这里发生了什么以及指挥部正在做什么。它基本上忽略第一行并选择其他记录来排序并删除其中的重复项。因此,我在输出文件的底部看到一个额外的标头。

我期待这样的输出。

ID,NAME,LOCATION
1,Vikrant,Gurgaon
22,abcd,Noida
2,Bharat,Noida
33,xyz,Hyderabad
3,Raju,Hyderabad

答案1

使用,和:bashheadtailsort

您可以将文件名保存在数组中,然后

  • 打印第一个文件的标题行
  • 输出从第 2 行开始的所有文件的内容以及sort带有 unique 选项的结果
  • 将输出重定向到文件
files=( *test*.csv )
{
  head -n1 "${files[0]}"
  for i in "${files[@]}"; do
    tail -n+2 "$i"
  done | sort -u
} > output

答案2

您不能依赖NR>1在所有文件之前使用和连接 cat {} +
像这样,我尝试尽可能重用您的代码:

{ 
    awk 'NR==1{print;exit}' *test*file*csv
    find . -type f -name '*test*file.csv' -exec awk 'NR>1' {} \; |
    sort -u
} > output.file

输出文件

ID,NAME,LOCATION
1,Vikrant,Gurgaon
22,abcd,Noida
2,Bharat,Noida
33,xyz,Hyderabad
3,Raju,Hyderabad

查找-exec {} +

-exec command {} +
-exec 操作的此变体对所选文件运行指定的命令,但命令行是通过在末尾附加每个所选文件名来构建的

所以已经串联起来了

答案3

只需执行以下操作:

find . -type f -name '*test*file.csv' -exec awk '!seen[$0]++' {} +

对于 awk 读取的每一行,如果它之前没有(!)在称为的关联数组中设置见过它将被添加到数组中,并且由于条件结果解析为“true”,因此该行将输出,如果 awk 读取任何同一行,则条件结果为“false”,因此它将跳过重复项;

在 awk$0中指的是整行,这里我们用作数组键,并且值将针对每个键(行)读取而递增。对于一行,如果它没有在数组中设置,则值为 0 并将被打印,如果键的值 >0 它将被跳过。

答案4

稍微修改一下你的命令行,我们将得到所需的输出:

awk 'NR<2||FNR>1' ./*test_file*.csv > temp ;
( head -n 1; sort -u; ) < temp > output.file

您的结果位于文件 output.file 中

相关内容