我想使用下面的脚本合并 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.csv
:input.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
将安排我们的内联脚本被多次调用,并从文件中读取批量参数。