在 UNIX 中用通配符比较两个数组

Compare two arrays with wild cards in UNIX

我正在尝试比较循环中的两个数组,一个数组包含文件名,另一个数组包含文件路径(包括文件名)。我无法在我的代码中使用通配符。如果我能以其他方式工作,请提出您的意见和建议。

.~/.env
defaultlist = ("file1" "file2" "file3") #contains only filename
checklist=/filepath=("${filename}"/*.csv) # second array which is extracts all csv files in the path

for i in "${defaultlist[@]}". #iterating default list
 do
  if [["$i" =~ "$checklist[@]}"]]
  then echo "$i   File present"
  else echo "$i   not present"
  fi
 done

为了更好地理解,上面的代码将只匹配两个列表中完全相同的名称,但在我的例子中,一个列表只有文件名,另一个列表有 filepath/filename 附加随机数。那么我们可以在比较两个数组时使用通配符吗?如果没有,还有其他方法可以实现我的目标吗?

两个数组的长度不同。

我不会使用 Bash 数组,但是 comm 实用程序:

$ ls
bar.csv baz.csv foo.csv
$
$ comm -12 <(printf '%s\n' {foo,bar}.csv | sort) <(printf '%s\n' *.csv)
bar.csv
foo.csv
  • comm 默认打印三列:仅在第一个文件中找到的行、仅在第二个文件中找到的行以及两者共有的行。 -12 标志是 -1 -2 的缩写,将删除前两列,从而只打印出第三列,其中包含两个文件共有的行[​​=41=]
  • <(...) 使用所附命令的输出创建一个临时文件(参见 process substitution
  • 我使用了 printf 这样我就可以轻松地打印参数列表,每个参数都在自己的行上 (\n)
  • comm 需要排序的行,这就是为什么那里有一个 sort

如果你需要在一个目录下比较它们,你可以直接在目录名前添加,像这样:

$ ls temp
bar.csv baz.csv foo.csv
$
$ comm -12 <(printf '%s\n' temp/{foo,bar}.csv | sort) <(printf '%s\n' temp/*.csv)
temp/bar.csv
temp/foo.csv

非精确匹配的解决方案可能如下所示:

check.sh
#!/usr/bin/env bash

shopt -so errexit
shopt -so nounset
shopt -s nullglob

declare -a prefixes=(foo bar missing)

for prefix in "${prefixes[@]}"; do
  echo "FILES WITH PREFIX: $prefix"

  # Build a glob pattern using the expected prefix and extension.
  for existing_file in "$prefix"*.csv; do
    # Ensure the expanded pattern is actually a file.
    if [[ -f "$existing_file" ]]; then
      echo "$existing_file"
    fi
  done

  echo
done

和示例执行:

$ ls
bar_123.csv  baz_3456.csv check.sh     foo_12.csv   foo_542.csv
$
$ ./check.sh 
FILES WITH PREFIX: foo
foo_12.csv
foo_542.csv

FILES WITH PREFIX: bar
bar_123.csv

FILES WITH PREFIX: missing

For better understanding, the above code will only match complete identical names in both lists…

不是真的,因为上面的代码格式不正确。

人们总是可以做一些丑陋和“二次方”(意思是${#defaultlist[@]} × ${#checklist[@]})复杂的事情来交叉匹配列表:

defaultlist=('file1' 'file2' 'file3')
checklist=("${defaultlist[@]/%/".$((RANDOM)).suffix"}")
checklist=("${checklist[@]/#/'/some/path/to/'}")
defaultlist+=('file4' 'file5')  # Not in checklist.

printf 'defaultlist: [%s]\nchecklist: [%s]\n\n' \
       "${defaultlist[*]}" "${checklist[*]}"

for name_fragment in "${defaultlist[@]}"; do
  for full_path in "${checklist[@]}"; do
    if [[ "${full_path##*/}" == *"$name_fragment"* ]]; then
      echo "${name_fragment} present"
      continue 2
    fi
  done
  echo "${name_fragment} NOT present"
done