正确的 bash 方式:
#!/bin/bash
# When using globs, always use either nullglob or failglob
shopt -s nullglob
# define your array fvar2
declare -a fvar2=( */ )
# Remove the trailing slash in each field of fvar2, and make an array fvar1 of it
declare -a fvar1=( "${fvar2[@]%/}" )
# Print each field of array fvar2, one field per line
printf '%s\n' "${fvar1[@]}"
对于带有有趣符号(空格、换行符等)的文件名,这是 100% 安全和防弹的。
现在让我稍微扩展一下这个答案,向您展示如何从另一个涉及更多处理的数组构建一个数组。通常,可以使用Shell Parameter Expansions完成简单的处理。但是,如果这还不够,例如,您只想保留从数组中每个字段的偏移量 7 开始的长度为 4 的子字符串array1
。解决方案
declare -a array2=( "${array1[@]:7:4}" )
将不起作用,因为这将占用 7 到 11 的字段array1
,正如您将在我上面给出的链接中看到的那样。在这里,您确实需要循环array1
,进行处理,然后将其推送到array2
. 您将这样做:
# empty and initialize array2
declare -a array2=()
for i in "${array2[@]}"; do
array2+=( "${i:7:4}" )
done
运算符将+=
连接 lhs 和 rhs 的数组,将结果放在 lhs 的数组中。看:
$ declare -a array1=( banana{00..10}gorilla )
$ printf '%s\n' "${array2[@]}"
banana00gorilla
banana01gorilla
banana02gorilla
banana03gorilla
banana04gorilla
banana05gorilla
banana06gorilla
banana07gorilla
banana08gorilla
banana09gorilla
banana10gorilla
$ declare -a array2=()
$ for i in "${array1[@]}"; do array2+=( "${i:7:4}" ); done
$ printf '%s\n' "${array2[@]}"
0gor
1gor
2gor
3gor
4gor
5gor
6gor
7gor
8gor
9gor
0gor
要求解释shopt -s nullglob
当使用 bash 的 glob 时,总是使用shopt -s nullglob
或者shopt -s failglob
你真的想要一个健壮的脚本。为什么?看:
$ shopt -u nullglob failglob # unsetting nullglob and failglob
$ echo there_are_no_files_matching_this_glob_in_this_directory_*
there_are_no_files_matching_this_glob_in_this_directory_*
如您所见,当 nullglob 和 failglob 未设置时,如果没有通配符匹配,bash 将逐字扩展 glob 到自身。这可能会导致脚本中出现可怕的东西,例如,如果您想重命名所有.txt
以前缀结尾的文件banana
,您会这样做……但是如果.txt
目录中没有以结尾的文件怎么办?
$ shopt -u nullglob failglob
$ for i in *.txt; do mv "$i" "banana$i.txt"; done
mv: cannot stat `*.txt': No such file or directory
$ # oh dear :(
是的,天哪:(
,因为您在没有控制其参数的情况下运行了一个命令……这可能很危险。
现在,如果你打开nullglob
,如果没有匹配,glob 将扩展为空!:)
. 看:
$ shopt -s nullglob; shopt -u failglob
$ for i in *.txt; do mv "$i" "banana$i.txt"; done
$ # Oh... nothing happened, great!
或者,如果您打开failglob
,并且没有匹配项,bash 将引发错误:
$ shopt -s failglob; shopt -u nullglob
$ for i in *.txt; do mv "$i" "banana$i.txt"; done
bash: no match: *.txt
$ # Good :)
并且循环永远不会被执行(这很好!你不想在不控制参数的情况下运行命令)。
如果两个都开呢?
$ shopt -s nullglob failglob
$ for i in *.txt; do mv "$i" "banana$i.txt"; done
bash: no match: *.txt
$ # Good :)
哦,failglob
好像赢了。
在您的情况下,我想如果没有目录,您希望您的数组真正为空。看:
$ # I'm in a directory with no subdirs
$ # I'm unsetting nullglob and failglob
$ shopt -u nullglob failglob
$ array=( */ )
$ declare -p array
declare -a array='([0]="*/")
$ # Oh dear, my array contains */ verbatim
$ # now, let's set nullglob
$ shopt -s nullglob
$ array=( */ )
$ declare -p array
declare -a array='()'
$ # Now array is truly empty! :)
$ # How about failglob?
$ shopt -u nullglob; shopt -s failglob
$ # You'll see the failure in $? look:
$ echo $?
0
$ # all is good about $?
$ array=( */ )
bash: no match: */
$ echo $?
1
$ # :)
但是failglob
你的数组不会被重置:
$ declare -a array=( some junk in my array )
$ declare -p array
declare -a array='([0]="some" [1]="junk" [2]="in" [3]="my" [4]="array")'
$ shopt -u nullglob; shopt -s failglob
$ array=( */ )
bash: no match: */
$ declare -p array
declare -a array='([0]="some" [1]="junk" [2]="in" [3]="my" [4]="array")'
$ # Ok, got it! :)