我的 Linux 目录包含文件转储,它们看起来像:
EDW_Infile_ABC_Daily_Activity_20190204.csv
EDW_Infile_ABC_Daily_Activity.zip
EDW_Infile_PQRInc_Daily_Activity_20190204.csv
EDW_Infile_PQRInc_Daily_Activity_zip
EDW_Infile_ABC_Daily_Payment_20190204.csv
EDW_Infile_PQRInc_Daily_Payment_20190204.csv
EDW_Infile_ABC_Daily_Status_20190204.csv
EDW_Infile_PQRInc_Daily_Status_20190204.csv
这些文件遵循一些常见的名称模式,例如
EDW_Infile_*<3 to 8 bytes company name>*_Daily_Activity_*YYYYMMDD*.csv
EDW_Infile_*<3 to 8 bytes company name>*_Daily_Payment_*YYYYMMDD*.csv
EDW_Infile_*<3 to 8 bytes company name>*_Daily_Status_*YYYYMMDD*.csv
我怎么能够 -
1) 查找所有客户、所有日期的所有文件,其遵循模式 EDW_Infile_{3 到 8 字节任意名称}_每日_活动_{任何日期}.csv
2) 每个文件都包含一个标头。如何将它们全部合并到一个文件中并且只有一个标头
答案1
我稍微介绍了我的 zsh 知识,以便更具体地回答,以防您无法控制文件名并且文件名为类似EDQ_Infile_some uninteresting stuff here_Daily_Activity_junk here.csv
,因此不想使用*
通配符。
要收集文件名列表...
遵循模式 EDW_Infile_{3 到 8 字节任意名称}_Daily_Activity_{任意日期}.csv
我会在 zsh 中设置这个 Extended_glob 模式(不要输入$
-- 这是 shell 提示符):
$ set -o extended_glob
$ files=(EDW_Infile_?(#c3,8)_Daily_Activity_[[:digit:]](#c8).csv)
除了纯文本之外,该模式是:
?
-- 任何(单个)字符(#c3,8)
-- 需要三到八个字符(含)[[:digit:]]
-- 需要一个数字(#c8)
-- 需要八个
查看列表:
$ print -l $files
EDW_Infile_ABC_Daily_Activity_20190204.csv
EDW_Infile_PQRInc_Daily_Activity_20190204.csv
到那时...
将它们全部合并到一个文件中,并且只有一个标头
{ head -1 "${files[1]}"; for f in $files; do sed 1d "$f"; done; } > output.csv
这会将两个命令分组并将其输出重定向到output.csv
.第一个命令head
,从数组中的第一个文件中获取第一行;然后第二个命令循环遍历所有文件并删除第一行(默认将剩余部分打印到标准输出)。
答案2
你可能想要这样的东西
# collect all the "EDW_Infile_ABC" prefixes
declare -A prefix
for f in EDQ_Infile_*_Daily_Activity_*.csv; do
p=${f%_*.csv}
prefix[$p]=1
done
for p in "${!prefixes[@]}"; do
awk 'NR==1 {print} FNR==1{next} {print}' "$p"_*.csv > "$p"_all.csv
zip "$p".zip "$p"_all.csv
rm "$p"_all.csv
done
对于 bash,关联数组需要版本 4。否则,我们可以使用位置参数。