如果我运行以下 grep 命令,我会得到我期望的输出:
$ grep -o -E '/ |:|\\|<|>|\*|\?|\"| $' <<< '/home/ttwaro/temp/Test/This is a Test: Testing Number 1?/This is Test: Testing Number 1?.eng.srt'
:
?
:
?
但是当我尝试将输出放入数组中时,我得到字符“C”而不是问号“?”。我究竟做错了什么?
$ array=()
$ array+=($(grep -o -E '/ |:|\\|<|>|\*|\?|\"| $' <<< '/home/ttwaro/temp/Test/This is a Test: Testing Number 1?/This is Test: Testing Number 1?.eng.srt'))
$ printf '%s\n' "${array[@]}"
:
C
:
C
答案1
发生这种情况的原因是因为您C
在运行命令的目录中有一个指定的文件或子目录,因此 glob?
会扩展以匹配它。用一个更简单的例子来说明:
$ ls -la
total 92
drwxr-xr-x 2 terdon terdon 16384 Mar 26 18:53 .
drwxr-xr-x 170 terdon terdon 73728 Mar 26 13:57 ..
$ array=( $( printf '?\n' ) )
$ printf '%s\n' "${array[@]}"
?
现在,我创建一个名为的文件C
并重试:
$ touch C
$ array=( $( printf '?\n' ) )
$ printf '%s\n' "${array[@]}"
C
这取决于操作顺序。当您运行 时array=( $( printf '?\n' ) )
,按顺序发生的事情是:
- 被
printf '?\n'
执行并返回一个?
. - 这未引用的
?
由 shell 扩展为任何匹配的文件名,在本例中称为C
. - 扩展后的 glob
C
被存储为0
数组 的元素array
。
为了避免这种情况,您需要引用数组赋值,以便保护任何通配符免受 shell 的影响:
$ array=( "$( printf '?\n' )" )
$ printf '%s\n' "${array[@]}"
?
或者,用你原来的例子:
$ array=( "$(grep -o -E '/ |:|\\|<|>|\*|\?|\"| $' <<< '/home/ttwaro/temp/Test/This is a Test: Testing Number 1?/This is Test: Testing Number 1?.eng.srt')" )
$ printf '%s\n' "${array[@]}"
:
?
:
?
然而,由于它被引用,整个结果显示为单个字符串,因此该数组将只有一个元素:
$ for ((i=0;i<${#array[@]}; i++)); do
printf 'element %s is %s\n' "$i" "${array[i]}";
done
element 0 is :
?
:
?
要将每个结果作为数组中的单独元素,您需要按照以下建议执行类似的操作戈登·戴维森在评论中:
$ readarray -t array < <(grep -o -E '/ |:|\\|<|>|\*|\?|\"| $' <<< '/home/ttwaro/temp/Test/This is a Test: Testing Number 1?/This is Test: Testing Number 1?.eng.srt')
$ for ((i=0;i<${#array[@]}; i++)); do
printf 'element %s is %s\n' "$i" "${array[i]}";
done
element 0 is :
element 1 is ?
element 2 is :
element 3 is ?
grep
这将避免引用的需要,因为shell 永远不会看到 的输出。
最后,结果中出现两个C
s 的原因是因为每个 s在存储到数组中时都?
扩展为 a :C
$ array=( ? ? ? )
$ printf '%s\n' "${array[@]}"
C
C
C