在元素中包含空格的Bash数组

abe*_*nky 136 unix arrays bash scripting

我正在尝试用我的相机在文件名的bash中构造一个数组:

FILES=(2011-09-04 21.43.02.jpg
2011-09-05 10.23.14.jpg
2011-09-09 12.31.16.jpg
2011-09-11 08.43.12.jpg)
Run Code Online (Sandbox Code Playgroud)

如您所见,每个文件名中间都有一个空格.

我已经尝试用引号括起每个名字,然后用反斜杠转义空格,两者都不起作用.

当我尝试访问数组元素时,它继续将空格视为elementdelimiter.

如何正确捕获名称中包含空格的文件名?

Dan*_*ego 110

我认为问题可能部分在于您如何访问元素.如果我做的很简单for elem in $FILES,我会遇到和你一样的问题.但是,如果我通过其索引访问数组,如果我以数字方式或使用转义符添加元素,则它可以工作:

for ((i = 0; i < ${#FILES[@]}; i++))
do
    echo "${FILES[$i]}"
done
Run Code Online (Sandbox Code Playgroud)

任何这些声明都$FILES应该有效:

FILES=(2011-09-04\ 21.43.02.jpg
2011-09-05\ 10.23.14.jpg
2011-09-09\ 12.31.16.jpg
2011-09-11\ 08.43.12.jpg)
Run Code Online (Sandbox Code Playgroud)

要么

FILES=("2011-09-04 21.43.02.jpg"
"2011-09-05 10.23.14.jpg"
"2011-09-09 12.31.16.jpg"
"2011-09-11 08.43.12.jpg")
Run Code Online (Sandbox Code Playgroud)

要么

FILES[0]="2011-09-04 21.43.02.jpg"
FILES[1]="2011-09-05 10.23.14.jpg"
FILES[2]="2011-09-09 12.31.16.jpg"
FILES[3]="2011-09-11 08.43.12.jpg"
Run Code Online (Sandbox Code Playgroud)

  • 当你可以使用`for f in"$ {FILES [@]}"`循环遍历元素时,没有必要遍历索引. (24认同)
  • @MarkEdgar我在$ {FILES [@]}**中遇到**的问题,当数组成员有空格时.似乎整个数组再次被重新解释,空间将现有成员分散为两个或更多元素.似乎""非常重要 (8认同)
  • 请注意,在使用数组元素时应使用双引号(例如`echo"$ {FILES [$ i]}"`).它对`echo`无关紧要,但对于任何使用它作为文件名的东西都是如此. (5认同)
  • 这里的另一个答案似乎更好:/sf/answers/636243051/ (2认同)
  • 我在六年前回答了这个问题,但我相信这是对数组FILES中的元素数量进行“计数”。 (2认同)

use*_*621 86

访问阵列项目的方式一定有问题.以下是它的完成方式:

for elem in "${files[@]}"
...
Run Code Online (Sandbox Code Playgroud)

bash手册页:

可以使用$ {name [subscript]}引用数组的任何元素....如果下标是@或*,则该单词将扩展为名称的所有成员.这些下标仅在单词出现在双引号内时有所不同.如果单词双引号, $ {名称[*]}扩展为与由IFS特殊变量的第一个字符分隔每个阵列成员的值的单个字,和$ {名称[@]}扩展的每个元素命名为单独的单词.

当然,访问单个成员时也应该使用双引号

cp "${files[0]}" /tmp
Run Code Online (Sandbox Code Playgroud)

  • 这一组中最干净,最优雅的解决方案,但应重新迭代,应引用数组中定义的每个元素. (3认同)
  • 来自其他编程语言的摘录中的术语很难理解.加上语法令人费解.如果你能再多说一点,我会非常感激吗?特别是`扩展为单个单词,每个数组成员的值由IFS特殊变量的第一个字符分隔 (3认同)
  • 当然,这些引用可以解决所有问题. (2认同)
  • 是的,同意双引号正在解决这个问题,这比其他解决方案更好。进一步解释一下 - 大多数其他人只是缺少双引号。你得到了正确的:`for elem in "${files[@]}"`,而他们有`for elem in ${files[@]}` - 所以空格混淆了扩展和在单个单词上运行的尝试。 (2认同)

Khu*_*eet 38

您需要使用IFS来停止空间作为元素分隔符.

FILES=("2011-09-04 21.43.02.jpg"
       "2011-09-05 10.23.14.jpg"
       "2011-09-09 12.31.16.jpg"
       "2011-09-11 08.43.12.jpg")
IFS=""
for jpg in ${FILES[*]}
do
    echo "${jpg}"
done
Run Code Online (Sandbox Code Playgroud)

如果你想分开的话.然后就做IFS ="." 希望它能帮到你:)

  • 我必须在阵列分配之前移动IFS ="",但这是正确的答案. (2认同)

mah*_*y67 13

上面已经回答了这个问题,但是这个答案有点简洁,并且手册页摘录有点神秘。我想提供一个完整的示例来演示这在实践中是如何工作的。

如果不加引号,数组只会扩展为由空格分隔的字符串,因此

for file in ${FILES[@]}; do
Run Code Online (Sandbox Code Playgroud)

扩展到

for file in 2011-09-04 21.43.02.jpg 2011-09-05 10.23.14.jpg 2011-09-09 12.31.16.jpg 2011-09-11 08.43.12.jpg ; do
Run Code Online (Sandbox Code Playgroud)

但是如果你引用扩展,bash 会在每个术语周围添加双引号,这样:

for file in "${FILES[@]}"; do
Run Code Online (Sandbox Code Playgroud)

扩展到

for file in "2011-09-04 21.43.02.jpg" "2011-09-05 10.23.14.jpg" "2011-09-09 12.31.16.jpg" "2011-09-11 08.43.12.jpg" ; do
Run Code Online (Sandbox Code Playgroud)

简单的经验法则是,如果您希望保留空格,请始终使用数组扩展而[@]不是引用数组扩展。[*]

为了进一步详细说明这一点,另一个答案中的手册页解释说,如果不加引号,$*$@行为相同,但引用时它们会有所不同。所以,给定

array=(a b c)
Run Code Online (Sandbox Code Playgroud)

然后$*两者$@都扩展到

a b c
Run Code Online (Sandbox Code Playgroud)

"$*"扩展到

"a b c"
Run Code Online (Sandbox Code Playgroud)

"$@"扩展到

"a" "b" "c"
Run Code Online (Sandbox Code Playgroud)


Dea*_*all 11

我同意其他人的意见,很可能你是如何访问问题的元素.在数组赋值中引用文件名是正确的:

FILES=(
  "2011-09-04 21.43.02.jpg"
  "2011-09-05 10.23.14.jpg"
  "2011-09-09 12.31.16.jpg"
  "2011-09-11 08.43.12.jpg"
)

for f in "${FILES[@]}"
do
  echo "$f"
done
Run Code Online (Sandbox Code Playgroud)

在表单的任何数组周围使用双引号"${FILES[@]}"将数组拆分为每个数组元素一个单词.除此之外,它不会进行任何分词.

使用"${FILES[*]}"也有一个特殊的含义,但是它将数组元素与$ IFS的第一个字符连接起来,产生一个单词,这可能不是你想要的.

使用裸露${array[@]}${array[*]}对扩展的结果进行进一步的分词,所以你最终会在空格(以及其他任何内容$IFS)上分割单词而不是每个数组元素一个单词.

使用C风格的循环也很好,如果你不清楚它,可以避免担心单词分裂:

for (( i = 0; i < ${#FILES[@]}; i++ ))
do
  echo "${FILES[$i]}"
done
Run Code Online (Sandbox Code Playgroud)


小智 7

如果你的数组是这样的:#!/bin/bash

Unix[0]='Debian'
Unix[1]="Red Hat"
Unix[2]='Ubuntu'
Unix[3]='Suse'

for i in $(echo ${Unix[@]});
    do echo $i;
done
Run Code Online (Sandbox Code Playgroud)

你会得到:

Debian
Red
Hat
Ubuntu
Suse
Run Code Online (Sandbox Code Playgroud)

我不知道为什么,但循环分解了空格并将它们作为一个单独的项目,即使你用引号将它括起来。

为了解决这个问题,不是调用数组中的元素,而是调用索引,它采用用引号括起来的完整字符串。它必须用引号括起来!

#!/bin/bash

Unix[0]='Debian'
Unix[1]='Red Hat'
Unix[2]='Ubuntu'
Unix[3]='Suse'

for i in $(echo ${!Unix[@]});
    do echo ${Unix[$i]};
done
Run Code Online (Sandbox Code Playgroud)

然后你会得到:

Debian
Red Hat
Ubuntu
Suse
Run Code Online (Sandbox Code Playgroud)