Bash for ls 루프는 "(" 문자에서 줄을 분할합니다.

Bash for ls 루프는 "(" 문자에서 줄을 분할합니다.

현재 저는 생성 날짜 순서대로 디렉터리의 특정 파일을 반복하도록 되어 있는 bash 스크립트를 작성 중입니다. 이를 위해 다음을 사용합니다(대신 실제 코드 사용 echo).

for i in $(ls -tr)
do
    echo $i
done

대부분의 경우 잘 작동합니다.

하지만 이제 스크립트를 손상시키는 파일 형식을 발견했습니다: aha_-_a ()a.txt.

파일 이름에는 공백과 여는 괄호 "("가 포함되어 있는데, 이는 개행을 실행하는 것처럼 보입니다. 결과는 다음과 같습니다.

aha_-_a
()a.txt

하지만 다음과 같아야 합니다.

aha_-_a ()a.txt

원하는 동작을 얻는 방법을 알고 있나요?

답변1

인용을 해제하면 $(ls -tr)확장 시 분할+glob이 호출됩니다.

분할은 $IFS문자(기본값은 SPC, TAB 및 NL)를 기준으로 수행되며 glob 부분은 문자에서 와일드카드를 찾고 해당 패턴과 일치하는 파일을 확장하려고 시도합니다.

ls여기서는 실제로 glob 부분을 수행하지 않고 NL 문자로 출력을 분할하려는 것처럼 보입니다 . 따라서 다음과 같아야 합니다.

IFS=$'\n' # split on NL only
set -o noglob # disable the glob part
for f in $(ls -tr); do
  printf '%s\n' "$f"
done

이는 SPC 문자가 포함된 파일에 대해 정상적으로 작동합니다. 그러나 파일 이름에 NL 문자가 있으면 여전히 작동하지 않습니다.

여기서는 zsh다음으로 전환하여 수행하는 것이 가장 좋습니다.

for f in *(NOm); do
  printf '%s\n' "$f"
done

여기서 glob 한정자를 사용하는 것처럼( (for ) 일치하는 파일이 없는 경우 오류를 방지하는 것처럼) *현재 디렉터리에서 숨겨지지 않은 모든 파일로 확장되고 기간을 기준으로 역순으로 정렬됩니다 .ls -rtOmNnullglob

또는 GNU가 있는 경우 다음을 ls수행하십시오 bash.

eval "files=($(ls --quoting-style=shell-always -rt))"
for f in "${files[@]}"; do
  printf '%s\n' "$f"
done

관련 정보