如何在Bash中将具有相同前缀名称的CSV文件打包成Zip文件?

3
假设我有许多 CSV 文件位于/home/user/test
123_24112021_DONG.csv
122_24112021_DONG.csv
145_24112021_DONG.csv
123_24112021_FINA.csv
122_24112021_FINA.csv
145_24112021_FINA.csv
123_24112021_INDEM.csv
122_24112021_INDEM.csv
145_24112021_INDEM.csv

如您所见,所有文件都有三个唯一的前缀:

145
123
122

我需要根据前缀创建zip文件,每个zip文件包含一个或多个csv文件。需要注意的是,实际上我不知道每个前缀下有多少个csv文件,这只是一个例子(每个前缀下有3个csv文件)。 我编写了一段代码,从Bash表中的所有csv文件名中提取前缀:

for entry in "$search_dir"/*
do
  # extract csv files
  f1=${entry##*/}
  echo $f1
  # extract prefix of each file
  f2=${f1%%_*}
  echo $f2
  # add prefix in table
  liste_sirets+=($f2)
done

# get uniq prefix in unique_sorted_list

unique_sorted_list=($(printf "%s\n" "${liste_sirets[@]}" | sort -u ))
echo $unique_sorted_list

这将产生以下结果:

145
123
122

现在我想将每个以相同前缀定义的三个文件压缩到同一个zip文件中: 换句话说,创建123_24112021_M2.zip,其中包含以下内容:
123_24112021_DONG.csv
123_24112021_FINA.csv
123_24112021_INDEM.csv

我开发了一个循环,它会关注本地路径中每个csv文件的前缀名称,然后压缩所有具有相同前缀名称的文件:

并且 122_24112021_M2.zip 145_24112021_M2.zip ...

for i in $unique_sorted_list
do
for j in "$search_dir"/*
do
if $(echo $j| cut -d'_' -f1)==$i
zip -jr $j
done

但是,它不起作用,有任何帮助,请!谢谢!

你可以先创建一个不同前缀的数组(为此目的使用关联数组而不是索引数组)。然后,在第二次遍历时,通过这个前缀列表收集所有具有该前缀的文件进行压缩。你不需要对它们进行排序。 - user1934428
@user1934428:确实,这就是我在我的回答中展示的。 - anubhava
2个回答

5

使用 bash 和 shell 工具:

#!/bin/bash

printf '%s\n' *_*.csv | cut -d_ -f1 | uniq |
while read -r prefix
do
        zip "$prefix".zip "$prefix"_*.csv
done

更新:
还要求按日期(文件名的第二部分)对文件进行分组:

#!/bin/bash

printf '%s\n' *_*_*.csv | cut -d_ -f2 | sort -u |
while read -r date
do
        zip "$date".zip ./*_"$date"_*.csv
done

Aydin,谢谢!!它有效,但我需要将DATE_M2添加到包名称中。换句话说,zip名称将是:prefix_DATE_M2.zip。 - SA2018
1
@SA2018 你可以在 while 循环中修改 zip 命令:zip "$prefix"_DATE_M2.zip "$prefix"_*.csv - M. Nejat Aydin
谢谢!还有一个问题,这个简单的 shell 命令是否可以在指定路径而不是实际路径创建 zip 包? - SA2018
1
@SA2018 zip /path/to/zips/"$prefix"_DATE_M2.zip "$prefix"_*.csv - M. Nejat Aydin
非常感谢你。 - SA2018
显示剩余3条评论

1

使用 bash 4+ 的关联数组:

# declare an associative array
declare -A unq

# store unique prefixes in array unq
for f in *_*.csv; do
   unq["${f%%_*}"]=1
done

# iterate through unq and create zip files
for i in "${!unq[@]}"; do
   zip "$i" "${i}_"*
done

谢谢您的回复,但是它不起作用,我没有在唯一数组中得到唯一前缀,第二次迭代会出现“zip error: Nothing to do! (5.zip) +zip 6 '6_*'” 的错误。在此提供信息,在执行您的命令之前,我指向了包含CSV文件的本地路径:cd $search_dir - SA2018
这是在我的bash 5.1.8上经过充分测试的解决方案。第一次循环后,declare -p unq显示什么? - anubhava
1
将脚本命名为“CreateZip.KSH”只会导致混淆,请考虑将其重命名为“CreateZip.sh”或“CreateZip.bash”,@SA2018。确保第一行不使用ksh(您的登录shell可以是任何东西,脚本的sh-bang行也可以是任何东西)。 - Jeff Schaller
declare is internal directive of bash and declare: not found instantly tells us your script is not using bash - anubhava
好的,我进行了刷新,现在显示另一个错误:uniq: full: must use subscript when assigning associative array,关于声明没有问题。 - SA2018
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接