从 bash 关联数组键中解压文件列表

Unzip list of files from bash associative array keys

我的 bash 脚本创建一个以文件为键的关联数组。

declare -A fileInFolder
for f in "${zipFolder}/"*".zip"; do
    read -r fileInFolder[$f] _ < <(md5sum "$f")
done

... code for removing some entry in fileInFolder ...

unzip -qqc "${!fileInFolder[@]}"

并且 unzip 阻止我 caution: filename not matched: 除了第一个文件之外的所有人。

以下命令可以正常工作:

unzip -qqc "${zipFolder}/"\*".zip"

我尝试使用 7z 但我没有找到将多个 zip 文件作为输入的方法(如果我的理解是正确的,请使用 -ai 选项 this need a list of file separated by new line.. .)

前言

这个答案基本上可以归结为 你不能用一个 unzip 命令来做到这一点 ,假设你知道你可以把 unzip -qqc "$f"在你在问题中写的 for 循环中,你出于某种原因不想这样做。

我的回答

您没有收到 所有 个文件的错误;相反,从 .

的第二个文件 开始,所有文件都出现错误

只需尝试以下操作

unzip -qqc file1.zip file2.zip

你会得到错误

caution: filename not matched:  file2.zip

这就是您得到的那个。

来自 unzipman 页面

SYNOPSIS
       unzip [-Z] [-cflptTuvz[abjnoqsCDKLMUVWX$/:^]] file[.zip] [file(s) ...]  [-x xfile(s) ...] [-d exdir]```

看来您只能在命令行上提供 一个 zip 文件。

嗯,其实不完全是,因为你可以在命令行上指定更多的 zip 文件,但是要这样做,你必须依赖 unzip 自己的解释方式自己的命令行;这部分模仿了 shell,但它所能做的全部都列在 man 页面中:

ARGUMENTS
       file[.zip]
              Path of the ZIP archive(s).  If the file specification is a wildcard, each matching file is processed in an order determined by  the
              operating system (or file system).  Only the filename can be a wildcard; the path itself cannot.  Wildcard expressions are similar to
              those supported in commonly used Unix shells (sh, ksh, csh) and may contain:

              *      matches a sequence of 0 or more characters

              ?      matches exactly 1 character

              [...]  matches any single character found inside the brackets; ranges are specified by a beginning character, a hyphen, and an ending
                     character.   If an exclamation point or a caret (`!' or `^') follows the left bracket, then the range of characters within the
                     brackets is complemented (that is, anything except the characters inside the brackets is considered a match).   To specify  a
                     verbatim left bracket, the three-character sequence ``[[]'' has to be used.

              (Be  sure to quote any character that might otherwise be interpreted or modified by the operating system, particularly under Unix and
              VMS.)  If no matches are found, the specification is assumed to be a literal filename; and if that also fails, the suffix .zip is ap‐
              pended.   Note that self-extracting ZIP files are supported, as with any other ZIP archive; just specify the .exe suffix (if any) ex‐
              plicitly. ```

因此,从技术上讲,您遇到了与 7z 相同的问题。

  • 忽略关联数组存储zip文件MD5的原因。
  • 正如@Enrico Maria De Angelis 指出的那样,unzip 每次调用只接受一个 zip 文件参数。因此,您不能将关联数组文件名索引扩展为单次调用 unzip.
  • 的参数

我提出这个解决方案:

#!/usr/bin/env bash

# You don't want to unzip the pattern name if none match
shopt -s nullglob

declare -A fileInFolder
for f in "${zipFolder}/"*".zip"; do
    # Store MD5 of zip file into assoc array fileInFolder
    # key: zip file name
    # value: md5sum of zip file
    read -r fileInFolder["$f"] < <(md5sum "$f")
    # Unzip file content to stdout
    unzip -qqc "$f"
done | {
 # Stream the for loop's stdout to the awk script
 awk -f script.awk
}

对所有 zip 文件仅调用一次 md5sum 的替代实现

shopt -s nullglob

# Iterate the null delimited entries output from md5sum
# Reading first IFS=' ' space delimited field as sum
# and remaining of entry until null as zipname
while IFS=' ' read -r -d '' sum zipname; do
  # In case md5sum file patterns has no match
  # It will return the md5sum of stdin with file name -
  # If so, break out of the while
  [ "$zipname" = '-' ] && break
  fileInFolder["$zipname"]="$sum"
  # Unzip file to stdout
  unzip -qqc -- "$zipname"
done < <(md5sum --zero -- "$zipFolder/"*'.zip' </dev/null) | awk -f script.awk