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