我正在编写一个脚本,该脚本将多个文件扩展名作为逗号分隔的字符串,并使用它来列出特定目录结构中的文件,但提供的扩展名数量可能会有所不同。
我正在使用的查找命令是
find ./ -type f \( -iname \*.ksh -o -iname \*.cfg \)
此处用户正在搜索 ksh 和 cfg 文件。但用户可能只能找到 ksh 、 cfg 或更多扩展。有没有办法使搜索模式对任意数量的扩展通用?
答案1
假设您将文件名后缀作为单独的命令行参数获取(有关如何处理逗号分隔字符串的信息,请参阅答案末尾):
#!/bin/sh
for suffix do
set -- "$@" -o -iname "*.$suffix"
shift
done
shift
find . -type f \( "$@" \)
该脚本将被称为
./script.sh ksh cfg
它会将$suffix
位置参数中的每个后缀替换为-o -iname "*.$suffix"
.
shift
调用之前的唯一的find
删除了首字母-o
in "$@"
。
ksh93
在or中使用数组bash
:
#!/bin/ksh
name_opts=()
for suffix do
name_opts+=( -o -iname "*.$suffix" )
done
find . -type f \( "${name_opts[@]:1}" \)
in:1
丢弃数组"${name_opts[@]:1}"
的第一个元素name_opts
(初始的-o
)。
如果您确实想要以逗号分隔的字符串形式获取后缀(这意味着您无法使用脚本来查找文件名后缀中带有逗号的文件,例如 RCS 或 CVS 存储中的文件),您可以转换该字符串, $list
, 到数组中bash
或ksh93
与
set -f
suffixes=( ${list//,/ } )
set +f
或sh
与
set -f
set -- $( printf '%s\n' "$list" | tr ',' ' ' )
set +f
或者
set -f; ifs=$IFS; IFS=','
set -- $list
set +f; IFS=$ifs; unset ifs
(这些将位置参数设置为后缀列表)。
这set -f
文件名生成(通配符),因为我们依赖 shell 在替换逗号的空格上分割字符串,但是不是使用生成的单词进行通配。如果没有,set -f
我们将无法正确处理对[ch]
或等后缀的请求*
。
bash
or中的循环ksh
将从
for suffix do ...
到
for suffix in "${suffixes[@]}"; do ...
而循环sh
将保持原样。
答案2
您可以使用扩展正则表达式来-iregex
代替多个段:-iname
GNU find
:
find . -type f -regextype egrep -iregex '.*\.(ksh|cfg)$'
免费BSD find
:
find -E . -type f -iregex '.*\.(ksh|cfg)$'
如果变量中已有逗号分隔的扩展名(例如$csep
),请将它们转换为正则表达式替换 ( |
)。第一的。例如
csep='ksh,sh,cfg,csv'
re="$(echo "$csep" | tr , '|')"
find . -type f -regextype egrep -iregex ".*\.($re)$"
#BSD: find -E . -type f -iregex ".*\.($re)$"
如果您需要支持其中包含逗号的扩展,您可以使用,sed
来代替tr
, 以允许反斜杠转义逗号 ( \,
)。例如
$ csep='ksh,sh,cfg,csv,c\,v'
$ re="$(echo "$csep" | sed -Ee 's/([^\]),/\1|/g')"
$ printf '%b\n' "$re"
ksh|sh|cfg|csv|c\,v