파일 이름에 공백이있는 문제


8

파일 목록에서 반복해서 무언가를하고 싶습니다. 문제의 파일은 이름에 공백이 있습니다.

david@david: ls -l
total 32
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha
-rw-rw-r-- 1 david david  0 Mai  8 11:55 haha~
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha (3rd copy)
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha (4th copy)
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha (5th copy)
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha (6th copy)
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha (7th copy)
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha (another copy)
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha (copy)

이제 각 파일을 통계하고 싶습니다.

david@david: echo '
for file in $(ls)
do
stat $file
done' | bash

(여러 줄 명령을 작성하려면 에코와 파이프를 사용합니다.)

그렇게하면 이름에 공백이없는 파일에서 올바르게 작동합니다. 하지만 다른 사람들은 ...

stat: cannot stat ‘(another’: No such file or directory
stat: cannot stat ‘copy)’: No such file or directory

변경 $(ls)"$(ls)"$file에게하는 것은 "$file"작동하지 않습니다. 어떡해?

편집하다:

echo '
for files in *
do
stat "$files"
done' | bash

트릭을 수행합니다! bash를 처음 접했을 때 가능한 한 간단하게 유지하고 싶습니다 . 문제를 해결하더라도 공백을 탈출하려고 시도 xargs하거나 솔루션을 사용 하거나 아무것도 사용하지 마십시오 read -r.

일부 사람들이 물었 듯이 : 예, 대신 이것을 사용하는 stat *것이 이상합니다. 그러나 나는 for 루프를 사용하여 bash의 많은 파일 이름에 동일한 명령을 적용하는 일반적인 방법을 찾고 싶었습니다. 그래서 stat약자 수 gzip, gpg또는 rm.


1
무슨 일이야 stat *? (;-)
Rmano


나는 단지 stat를 예로 사용합니다. :) ls로 파일 이름을 수집하고 bash 루프에서 ls 결과를 사용하고 싶습니다.
user258532

답변:


12

의 여러 인용문 echo '은 문제를 복잡하게 만듭니다.

당신은 단지 사용할 수 있습니다 :

for f in *; do stat -- "$f"; done

또한

stat -- * 

... 그리고 파일을 모으고 명령을 적용하려면 (이유는 무엇입니까?)

for f in *; do echo "$f"; done | xargs stat --

당신이 너무 파일을 숨겨진하려면 ... 그리고, 단지 사용 * .*패턴으로,하지만 그 기억 ...세트에있을 것입니다 .

제쳐두고, 당신은 ls출력을 구문 분석해서는 안됩니다 .


(1) 그러나 줄 바꿈이있는 파일 이름이 있다면 다소 가치가 있습니다 ... ;-)


"그리고 명령을 적용하십시오 (왜?)"-> stat은 파일 이름으로 bash 루프를 수행하는 방법을 시도하고 있기 때문에 임의의 명령으로 사용됩니다. gpg, gzip 또는 다른 것이 될 수 있습니다.
user258532

@ user258532 명령에 관계없이 항상을 사용하십시오 for f in *; do command "$f"; done. 구문 분석하지 마십시오 ls. 반드시 for 루프 에서 사용하지 않는 이유는 echo무엇입니까?
terdon

echo : 여러 줄에 명령을 쓰는 것을 좋아하기 때문에 ... :)
user258532

2
응? 왜 에코가 필요합니까? Enter 키를 누르고 줄 바꿈을 계속하십시오. 당신은 열린 인용과 함께 줄을 종료하거나 중 하나에 경우 do, |, &&등, 당신은 새로운 라인에서 작업을 계속할 수 있습니다. 또는 heredocs를 사용하십시오. 사용할 이유가 없으며 echo문제를 일으킬 수도 있습니다.
terdon

"Enter를 누르고 줄 바꿈을 계속하십시오." 아야. :-D 이제 내 IQ는 공식적으로 0보다 낮습니다. 아시다시피, 저는 배쉬에 익숙하지 않습니다. 그러나 실제로 R (통계 스위트 및 스크립팅 언어)으로 돈을 벌고 있습니다.
user258532

6

참고 사항 : 공백을 추가하고 백 슬래시를 추가 Enter하고 새 줄에 쓰려고 할 때마다 적중하여 길고 복잡한 명령을 여러 줄로 나눌 수 있습니다 echo [...] | bash. 또한 공백이 포함 된 파일 이름의 경우 깨지지 $file않도록 큰 따옴표로 묶어야 stat합니다.

for file in $(ls); \
do \
stat "$file"; \
done

문제는 $(ls)공백을 포함하는 파일 이름 목록으로 확장되며에서도 마찬가지입니다 "$(ls)".

이 문제를 해결 하더라도이 방법은 백 슬래시가 포함 된 파일 이름과 줄 바꿈이 포함 된 파일 이름 (terdon으로 지적 됨)에서 여전히 중단됩니다.

두 문제에 대한 해결책은 파이프에 출력 될 것이다 find(A)에 while실행하는 반복 read -r, 각 반복에 있도록, read -r한 줄 저장할 find로 출력 S ' $file:

find . -maxdepth 1 -type f | while read -r file; do \
    stat "$file"; \
done

1
숨겨진 파일? :)
AB

5
줄 바꿈이 포함 된 파일 이름에서는 여전히 실패합니다. 파싱하지 마십시오 ls. 이제까지.
terdon

4
@ user258532 아닙니다. 진지하게, 구문 분석하지 마십시오ls . 더 좋고 더 강력한 방법이 있습니다. 이 글을 읽고 싶을 수도 있습니다 : 왜 * ls *를 구문 분석하지 않습니까? 자세한 사항은.
terdon

1
여기서 문제가 아닌 ls, 그것은이다 for- for을 반복 (IFS 구분) 단어 애프터 주어진 inkeyword`
글렌 잭맨

1
@glennjackman 아니라 네, 그것은의 조합이다 forls. for f in *예를 들어 괜찮을 것입니다.
terdon

3

오래된 find파일을 사용하고 숨겨진 파일, 줄 바꿈 및 공백으로 작업하십시오.

find . -print0 | xargs -I {} -0 stat {}

또는 대신에 다른 stat

find . -print0 | xargs -I {} -0 file {}
find . -print0 | xargs -I {} -0 cat {}

1

R 사람으로서 이미 R에서 해결 방법을 찾았습니다.

filenames <- dir(); # reads file names into an array.
                    # It works also recursively
                    # with dir(recursive=TRUE)
for (i in 1:length(filenames)) {
system(     # calls a system function
 paste(     # join stat and the file name
  "stat",
  filenames[i]
 )
)
}

알아, 화가 났어 나는의 출력이 원하는 ls구문 분석에 쉬울 것 ... R 공백을 처리 할 수 DIR ()를 인용 문자 값을 반환하기 때문에. 따옴표 사이의 모든 것은 공백이있는 유효한 파일 이름입니다.


3
귀찮게하지 마십시오 (그러나 노력을 위해 +1하십시오! :). 을 사용 for f in *하고 Enter 키를 누른 다음 새 줄을 계속하십시오 : do, stat "$f"다시 done입력하십시오. 그것은 4 줄로 멋지게 분할 된 명령이며 어떤 종류의 파일 이름에서도 깨지지 않습니다.
terdon

1

for 루프에서 공백 문제의 다른 인스턴스에 부딪 쳤으므로 다음과 같은 (imo보다 강력한) 명령이 일반적으로 사용됩니다. 파이프에도 잘 맞습니다.

$ ls | while read line; do stat "$line"; done;

이것을 결합 grep하거나 find대신 사용할 수 있습니다 .

$ find ./ -maxdepth 2 | grep '^\./[/a-z]+$' | while read line; do stat "$line"; done;

첫 번째 대답은 백 슬래시 또는 선행 또는 후행 공백이 포함 된 파일 이름에서 실패합니다. 에 -E옵션을 추가하지 않으면 두 번째 대답이 완전히 실패합니다. grep그렇지 않으면 +정규식으로 인식되지 않습니다 . 그럼에도 불구 grep 하고 공백이 포함 된 파일 이름을 제거 하기 때문에이 질문에 대한 스윙과 누락입니다 . 또한 질문의 예와 같이 숫자 (숫자)와 문장 부호 (예 : 괄호)가 포함 된 파일 이름을 제거합니다. 그리고 그것은 개행 문자를 포함하거나 -(대시)로 시작하는 파일 이름을 언급하지도 않습니다 .
Scott

-1

이 답변은 구문 분석 문제를 해결 ls하고 백 스페이스와 줄 바꾸기를 처리합니다.

이를 시도하면 Internal Field Separator IFS를 사용하여 문제를 해결할 수 있습니다.

IFS="\n" for f in $(ls); do   stat "$f"; done

그러나 또한 ls 출력을 구문 분석 할 필요없이 쉽게 해결할 수 있습니다.

for f in *; do   stat "$f"; done

1
숨겨진 파일에는 작동하지 않습니다.
AB

2
OP는 숨겨진 파일을 요청하지 않았습니다
Maythux

1
IFS여기 에서 수정해야하는지 알 수 없습니다 . 변수를 인용하면 단어 분리를 방지하기에 충분해야합니다.
스틸 드라이버

파싱 ls 합니다.
Maythux

downvote는 무엇인가 !!!
Maythux

-1

대신 공백을 밑줄과 같은 다른 문자로 바꾸어 파일 이름을 바꿀 수 있으므로이 문제를 제거 할 수 있습니다.

그렇게하려면 명령을 쉽게 실행하십시오.

for file in * ; do mv "$f" "${f// /_}" ; done
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.