I'm trying to construct an array in bash of the filenames from my camera:
我正在尝试构造一个数组在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)
As you can see, there is a space in the middle of each filename.
如您所见,每个文件名中间都有一个空格。
I've tried wrapping each name in quotes, and escaping the space with a backslash, neither of which works.
我试过把每个名字都用引号括起来,然后用反斜杠来转义空格,这两种方法都不管用。
When I try to access the array elements, it continues to treat the space as the elementdelimiter.
当我尝试访问数组元素时,它继续将空间视为elementdelimiter。
How can I properly capture the filenames with a space inside the name?
如何在文件名中使用空格正确地捕获文件名?
7 个解决方案
#1
81
I think the issue might be partly with how you're accessing the elements. If I do a simple for elem in $FILES
, I experience the same issue as you. However, if I access the array through its indices, like so, it works if I add the elements either numerically or with escapes:
我认为问题可能在一定程度上在于如何访问元素。如果我在$ file中为elem做一个简单的操作,我也会遇到与您相同的问题。但是,如果我通过它的索引访问数组,就像这样,如果我用数字或转义的方式添加元素,它就会工作:
for ((i = 0; i < ${#FILES[@]}; i++))
do
echo "${FILES[$i]}"
done
Any of these declarations of $FILES
should work:
这些$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)
or
或
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")
or
或
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"
#2
72
There must be something wrong with the way you access the array's items. Here's how it's done:
访问数组的方式一定有问题。如何做:
for elem in "${files[@]}"
...
From the bash manpage:
从bash从:
Any element of an array may be referenced using ${name[subscript]}. ... If subscript is @ or *, the word expands to all members of name. These subscripts differ only when the word appears within double quotes. If the word is double-quoted, ${name[*]} expands to a single word with the value of each array member separated by the first character of the IFS special variable, and ${name[@]} expands each element of name to a separate word.
数组的任何元素都可以使用${name[下标]}来引用。如果下标为@或*,则该词扩展为所有名称成员。只有当单词出现在双引号中时,这些下标才会有所不同。如果单词是双引号的,${name[*]}扩展为单个单词,每个数组成员的值由IFS特殊变量的第一个字符分隔,${name[@]}将每个元素的名称扩展为单独的单词。
Of course, you should also use double quotes when accessing a single member
当然,在访问单个成员时也应该使用双引号
cp "${files[0]}" /tmp
#3
33
You need to use IFS to stop space as element delimiter.
您需要使用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
If you want to separate on basis of . then just do IFS="." Hope it helps you:)
如果你想分开的话。然后就做IFS = "。"希望它能帮助你:)
#4
9
I agree with others that it's likely how you're accessing the elements that is the problem. Quoting the file names in the array assignment is correct:
我同意其他人的观点,问题可能在于你如何访问元素。在数组赋值中引用文件名是正确的:
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
Using double quotes around any array of the form "${FILES[@]}"
splits the array into one word per array element. It doesn't do any word-splitting beyond that.
在表单“${file[@]}”的任何数组中使用双引号将数组分割为每个数组元素的一个单词。除此之外,它不做任何分词。
Using "${FILES[*]}"
also has a special meaning, but it joins the array elements with the first character of $IFS, resulting in one word, which is probably not what you want.
使用“${FILES[*]}”也有一个特殊的含义,但是它将数组元素与$IFS的第一个字符连接起来,结果是一个单词,这可能不是您想要的。
Using a bare ${array[@]}
or ${array[*]}
subjects the result of that expansion to further word-splitting, so you'll end up with words split on spaces (and anything else in $IFS
) instead of one word per array element.
使用一个空的${array[@]}或${array[*]}将该扩展的结果设置为进一步的分词,因此您将以空格(以及$IFS中的任何其他内容)上的分词结束,而不是每个数组元素上的一个词。
Using a C-style for loop is also fine and avoids worrying about word-splitting if you're not clear on it:
使用c风格的for循环也是可以的,如果你不清楚的话,也可以避免担心分词:
for (( i = 0; i < ${#FILES[@]}; i++ ))
do
echo "${FILES[$i]}"
done
#5
2
Escaping works.
逃避工作。
#!/bin/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)
echo ${FILES[0]}
echo ${FILES[1]}
echo ${FILES[2]}
echo ${FILES[3]}
Output:
输出:
$ ./test.sh
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
Quoting the strings also produces the same output.
引用字符串也会产生相同的输出。
#6
1
Not exactly an answer to the quoting/escaping problem of the original question but probably something that would actually have been more useful for the op:
这并不是对原问题的引用/转义问题的回答,但可能对op更有用:
unset FILES
for f in 2011-*.jpg; do FILES+=("$f"); done
echo "${FILES[@]}"
Where of course the expression would have to be adopted to the specific requirement (e.g. *.jpg
for all or 2001-09-11*.jpg
for only the pictures of a certain day).
当然,该表达式必须被用于特定的需求(例如:*.jpg所有或2001-09-11*.jpg,只适用于某一天的图片)。
#7
0
Another solution is using a "while" loop instead a "for" loop:
另一个解决方案是使用“while”循环而不是“for”循环:
index=0
while [ ${index} -lt ${#Array[@]} ]
do
echo ${Array[${index}]}
index=$(( $index + 1 ))
done
#1
81
I think the issue might be partly with how you're accessing the elements. If I do a simple for elem in $FILES
, I experience the same issue as you. However, if I access the array through its indices, like so, it works if I add the elements either numerically or with escapes:
我认为问题可能在一定程度上在于如何访问元素。如果我在$ file中为elem做一个简单的操作,我也会遇到与您相同的问题。但是,如果我通过它的索引访问数组,就像这样,如果我用数字或转义的方式添加元素,它就会工作:
for ((i = 0; i < ${#FILES[@]}; i++))
do
echo "${FILES[$i]}"
done
Any of these declarations of $FILES
should work:
这些$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)
or
或
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")
or
或
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"
#2
72
There must be something wrong with the way you access the array's items. Here's how it's done:
访问数组的方式一定有问题。如何做:
for elem in "${files[@]}"
...
From the bash manpage:
从bash从:
Any element of an array may be referenced using ${name[subscript]}. ... If subscript is @ or *, the word expands to all members of name. These subscripts differ only when the word appears within double quotes. If the word is double-quoted, ${name[*]} expands to a single word with the value of each array member separated by the first character of the IFS special variable, and ${name[@]} expands each element of name to a separate word.
数组的任何元素都可以使用${name[下标]}来引用。如果下标为@或*,则该词扩展为所有名称成员。只有当单词出现在双引号中时,这些下标才会有所不同。如果单词是双引号的,${name[*]}扩展为单个单词,每个数组成员的值由IFS特殊变量的第一个字符分隔,${name[@]}将每个元素的名称扩展为单独的单词。
Of course, you should also use double quotes when accessing a single member
当然,在访问单个成员时也应该使用双引号
cp "${files[0]}" /tmp
#3
33
You need to use IFS to stop space as element delimiter.
您需要使用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
If you want to separate on basis of . then just do IFS="." Hope it helps you:)
如果你想分开的话。然后就做IFS = "。"希望它能帮助你:)
#4
9
I agree with others that it's likely how you're accessing the elements that is the problem. Quoting the file names in the array assignment is correct:
我同意其他人的观点,问题可能在于你如何访问元素。在数组赋值中引用文件名是正确的:
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
Using double quotes around any array of the form "${FILES[@]}"
splits the array into one word per array element. It doesn't do any word-splitting beyond that.
在表单“${file[@]}”的任何数组中使用双引号将数组分割为每个数组元素的一个单词。除此之外,它不做任何分词。
Using "${FILES[*]}"
also has a special meaning, but it joins the array elements with the first character of $IFS, resulting in one word, which is probably not what you want.
使用“${FILES[*]}”也有一个特殊的含义,但是它将数组元素与$IFS的第一个字符连接起来,结果是一个单词,这可能不是您想要的。
Using a bare ${array[@]}
or ${array[*]}
subjects the result of that expansion to further word-splitting, so you'll end up with words split on spaces (and anything else in $IFS
) instead of one word per array element.
使用一个空的${array[@]}或${array[*]}将该扩展的结果设置为进一步的分词,因此您将以空格(以及$IFS中的任何其他内容)上的分词结束,而不是每个数组元素上的一个词。
Using a C-style for loop is also fine and avoids worrying about word-splitting if you're not clear on it:
使用c风格的for循环也是可以的,如果你不清楚的话,也可以避免担心分词:
for (( i = 0; i < ${#FILES[@]}; i++ ))
do
echo "${FILES[$i]}"
done
#5
2
Escaping works.
逃避工作。
#!/bin/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)
echo ${FILES[0]}
echo ${FILES[1]}
echo ${FILES[2]}
echo ${FILES[3]}
Output:
输出:
$ ./test.sh
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
Quoting the strings also produces the same output.
引用字符串也会产生相同的输出。
#6
1
Not exactly an answer to the quoting/escaping problem of the original question but probably something that would actually have been more useful for the op:
这并不是对原问题的引用/转义问题的回答,但可能对op更有用:
unset FILES
for f in 2011-*.jpg; do FILES+=("$f"); done
echo "${FILES[@]}"
Where of course the expression would have to be adopted to the specific requirement (e.g. *.jpg
for all or 2001-09-11*.jpg
for only the pictures of a certain day).
当然,该表达式必须被用于特定的需求(例如:*.jpg所有或2001-09-11*.jpg,只适用于某一天的图片)。
#7
0
Another solution is using a "while" loop instead a "for" loop:
另一个解决方案是使用“while”循环而不是“for”循环:
index=0
while [ ${index} -lt ${#Array[@]} ]
do
echo ${Array[${index}]}
index=$(( $index + 1 ))
done