尝试将 grep 命令的输出放入 bash 数组中

尝试将 grep 命令的输出放入 bash 数组中

如果我运行以下 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' ) ),按顺序发生的事情是:

  1. printf '?\n'执行并返回一个?.
  2. 未引用的 ?由 shell 扩展为任何匹配的文件名,在本例中称为C.
  3. 扩展后的 globC被存储为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 永远不会看到 的输出。

最后,结果中出现两个Cs 的原因是因为每个 s在存储到数组中时都?扩展为 a :C

$ array=( ? ? ? )
$ printf '%s\n' "${array[@]}"
C
C
C

相关内容