요소에 공백이있는 배쉬 배열
카메라에서 파일 이름을 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)
보다시피, 각 파일 이름 중간에 공백이 있습니다.
각 이름을 따옴표로 묶고 백 슬래시로 공백을 이스케이프 처리하려고 시도했지만 둘 다 작동하지 않습니다.
배열 요소에 액세스하려고하면 공간을 요소 구분 기호로 계속 취급합니다.
이름 안에 공백이있는 파일 이름을 올바르게 캡처하려면 어떻게해야합니까?
요소에 액세스하는 방법에 부분적으로 문제가 있다고 생각합니다. 간단한 작업을 수행 for elem in $FILES
하면 동일한 문제가 발생합니다. 그러나 인덱스를 통해 배열에 액세스하면 요소를 숫자 또는 이스케이프로 추가하면 작동합니다.
for ((i = 0; i < ${#FILES[@]}; i++))
do
echo "${FILES[$i]}"
done
이러한 선언 $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)
또는
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")
또는
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"
배열의 항목에 액세스하는 방식에 문제가 있어야합니다. 방법은 다음과 같습니다.
for elem in "${files[@]}"
...
로부터 배쉬 맨 페이지 :
배열의 모든 요소는 $ {name [subscript]}를 사용하여 참조 할 수 있습니다. ... 첨자가 @ 또는 * 인 경우 단어가 모든 이름 구성원으로 확장됩니다. 이 첨자는 단어가 큰 따옴표로 묶인 경우에만 다릅니다. 단어가 큰 따옴표로 묶인 경우 $ {name [*]}은 각 배열 구성원의 값을 IFS 특수 변수의 첫 문자로 구분하여 단일 단어로 확장하고 $ {name [@]}은 별도의 단어로 이름을 지정합니다 .
물론 단일 멤버에 액세스 할 때는 큰 따옴표를 사용해야합니다.
cp "${files[0]}" /tmp
공간을 요소 분리 문자로 중지하려면 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
를 기준으로 분리하려는 경우. 그런 다음 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"
)
for f in "${FILES[@]}"
do
echo "$f"
done
양식의 배열 주위에 큰 따옴표를 사용 "${FILES[@]}"
하면 배열을 배열 요소 당 하나의 단어로 분할합니다. 그 이상으로 단어를 나누지 않습니다.
사용 "${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.
Using a C-style for loop is also fine and avoids worrying about word-splitting if you're not clear on it:
for (( i = 0; i < ${#FILES[@]}; i++ ))
do
echo "${FILES[$i]}"
done
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.
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:
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).
If you had your array like this: #!/bin/bash
Unix[0]='Debian'
Unix[1]="Red Hat"
Unix[2]='Ubuntu'
Unix[3]='Suse'
for i in $(echo ${Unix[@]});
do echo $i;
done
You would get:
Debian
Red
Hat
Ubuntu
Suse
I don't know why but the loop breaks down the spaces and puts them as an individual item, even you surround it with quotes.
To get around this, instead of calling the elements in the array, you call the indexes, which takes the full string thats wrapped in quotes. It must be wrapped in quotes!
#!/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
Then you'll get:
Debian
Red Hat
Ubuntu
Suse
Another solution is using a "while" loop instead a "for" loop:
index=0
while [ ${index} -lt ${#Array[@]} ]
do
echo ${Array[${index}]}
index=$(( $index + 1 ))
done
If you aren't stuck on using bash
, different handling of spaces in file names is one of the benefits of the fish shell. Consider a directory which contains two files: "a b.txt" and "b c.txt". Here's a reasonable guess at processing a list of files generated from another command with bash
, but it fails due to spaces in file names you experienced:
# bash
$ for f in $(ls *.txt); { echo $f; }
a
b.txt
b
c.txt
With fish
, the syntax is nearly identical, but the result is what you'd expect:
# fish
for f in (ls *.txt); echo $f; end
a b.txt
b c.txt
It works differently because fish splits the output of commands on newlines, not spaces.
If you have a case where you do want to split on spaces instead of newlines, fish
has a very readable syntax for that:
for f in (ls *.txt | string split " "); echo $f; end
참고URL : https://stackoverflow.com/questions/9084257/bash-array-with-spaces-in-elements
'development' 카테고리의 다른 글
PHP로 URL 재 작성 (0) | 2020.06.28 |
---|---|
장고 필터 대 단일 객체 얻기? (0) | 2020.06.28 |
JSON 객체의 항목이“json.dumps”를 사용하여 순서가 잘못 되었습니까? (0) | 2020.06.28 |
영문자와 만 일치하는 정규식 (0) | 2020.06.28 |
Windows 서비스로서의 .NET 콘솔 어플리케이션 (0) | 2020.06.28 |