用元素中的空格对数组进行攻击

时间:2021-12-23 16:51:35

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