mrj*_*per 2 scripting bash shell-script
我已经看到有关如何遍历多个文件扩展名的各种主题,但在大多数情况下,列表已定义。
例子:
for file in ${arg}/**/*.{txt,h,py}
do
....
done
Run Code Online (Sandbox Code Playgroud)
可以看出,.TXT文件将被忽略。可悲的是,回答它的人说它只适用于 bash4。但我的设置使用 bash3.x。
关于如何做到这一点的任何想法?
在bash你可以设置nocaseglob:
shopt -s nocaseglob
for file in "$arg"/**/*.{txt,h,py}
do
....
done
shopt -u nocaseglob
Run Code Online (Sandbox Code Playgroud)
noclaseglob可以在bash2.01以后的任何版本中使用,但是**需要bash4.0 或更高版本(并且它遵循符号链接,直到bash4.3 已修复)。请注意对引号的更正,$arg因为如果其中包含空格或通配符,则会出现问题。
不使用**您可以执行以下操作:
find "$arg" \( -iname '*.txt' -o -iname '*.h' -o -iname '*.py' \) -exec bash -c '
for file; do
...
done' bash {} +
Run Code Online (Sandbox Code Playgroud)
This will find all the files you are looking for and pass them as separate arguments to a new bash instance, which will then loop through them. If your per file operation is a single command, you can probably skip the new bash instance and use the command directly.
As per Stephane's comments below, the POSIX compatible solution is:
find "$arg" \( -name '*.[tT][xX][tT]' -o -name '*.[hH]' -o -name '*.[pP][yY]' \) \
-exec sh -c '
for file do
...
done' sh {} +
Run Code Online (Sandbox Code Playgroud)
Use zsh instead:
setopt extendedglob
for f ($arg/**/*.(#i)(txt|h|py)(N.)) {
...
}
Run Code Online (Sandbox Code Playgroud)
**/: any level of subdirectories(#i) is to turn case insensitive matching on for the rest of the glob (like ~(i) in ksh93).(N.) is the glob qualifier. N is to not return an error if there's no matching file and . to select regular files only (the equivalent of find's -type f)). You could add a D in there to also match dot (hidden) files and descend into hidden dirs (like find would be default).