0

此脚本应将文件夹存储在 fvar2 的目录中folder1/ folder2/ folder3/ ,然后folder1 folder2 folder3使用“sed”命令在 fvar1 中回显。最后它应该回显新数组 fvar1 中的所有目录

这是错误

./test.sh: line 18: syntax error near unexpected token ``echo "${fvar2[svar3]}" | sed 's#/##g'`'
./test.sh: line 18: `{fvar1[svar4]}=(`echo "${fvar2[svar3]}" | sed 's#/##g'`)'

这是脚本

#!/bin/bash

fvar2=(*/)
svar3=0
svar4=0

while true
do

{fvar1[svar4]}=(`echo "${fvar2[svar3]}" | sed 's#/##g'`)
svar3=`expr $svar3 + 1`
svar4=`expr $svar4 + 1`
echo "${fvar1[svar4]}"

done
4

1 回答 1

2

正确的 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! :)
于 2013-11-10T16:40:52.723 回答