连接具有相同结构的文件,仅保留第一个文件的标头

连接具有相同结构的文件,仅保留第一个文件的标头

我想使用下面的脚本合并 28 个具有不同名称和相同数据结构的文件:

$ cp mohan.csv Consolidate.csv
$ for fname in line
    do 
      cat $fname | sed '1d' >> Consolidate.csv
    done < input.txt

input.txt包含:

mohan.csv
babu.csv
mahesh.csv
datvik.csk
... etc

$ cat mohan.csv
no,name,dept
1,xyz,hr
2,abc,sales

我的脚本的输出:

$ cat Consolidate.csv
no,name,dept
1,xyz,hr
2,abc,sales
babu.csv
mahesh.csv
datvik.csk
... etc

请在这件事上给予我帮助。

答案1

您可以使用多种工具来完成这项工作。我假设您想保留第一个标头并删除其他标头。因此,只需附加到未更改的第一个文件,同时删除其他文件中的标头即可。

摆脱mohan.csvinput.txt

$ cat input.txt
babu.csv
mahesh.csv
datvik.csk
... etc

然后:

$ cp mohan.csv consolidate.csv
$ for file in "$(<input.txt)"; do
    sed '/no,name,dept/d' "$file" >> consolidate.csv
  done

或者与read

$ cp mohan.csv consolidate.csv
$ while read -r file; do
    sed '/no,name,dept/d' "$file" >> consolidate.csv
  done <  input.txt

或者,更简单,sed可以在以下位置找到纯粹的答案https://unix.stackexchange.com/a/204343/72707

答案2

怎么样

awk 'NR==1 || FNR > 1' $(< input.txt )

不要引用“命令替换”,这样它会在 的命令行上生成文件名列表awk(直到 LINE_MAX 系统配置参数)。如果您的文件名包含空格字符,请恢复为数组:

readarray -t Arr < input.txt
awk 'NR==1 || FNR > 1' "${Arr[@]}"

如果您的标题跨越多行,请调整脚本中要比较的两个数字awk

答案3

该解决方案假设文件列表可能比单次调用某些外部命令可以处理的文件长(因此无法一次性input.txt在命令行上列出文件名)。

假设位置参数列表(即某些脚本的参数列表)包含我们想要连接的文件的路径名列表,并且我们只想从其中的第一个中获取标头,如果输出文件尚不存在。如果输出文件已经存在,我们可以假设标头已经写入输出。

在 shell 中执行此操作的最少代码如下

[ ! -e outfile ] && head -n 1 -- "$1" >outfile
awk 'FNR != 1' "$@" >>outfile

此处,head -n 1用于仅从第一个文件中获取标头并将其写入到 中outfile(如果该文件outfile尚不存在)。然后,awk用于从所有文件中提取除第一行之外的所有行,并将这些行附加到outfile.

这个小脚本可以使用input.txt文件中的所有输入文件执行,假设文件名input.txt被正确引用或以其他方式“简单”(没有嵌入的空白字符或引号):

xargs sh -c '
    out=$1; shift
    [ ! -e "$out" ] && head -n 1 -- "$1" >"$out"
    awk "FNR != 1" "$@" >>"$out"
' sh Consolidate.csv <input.txt

这用于xargs运行一个小型内联sh -c脚本,将输入input.txt作为参数。输出文件名作为第一个参数给出并在内联脚本中Consolidate.csv接收。out

如果列表input.txt很长,xargs将安排我们的内联脚本被多次调用,并从文件中读取批量参数。

相关内容