단순 파일 루프 - "파일 이름이 너무 깁니다"

단순 파일 루프 - "파일 이름이 너무 깁니다"

저는 가장 기본적인 작업, 즉 특정 폴더의 모든 파일에 대해 하나 이상의 명령을 실행하려고 합니다.

이 경우 macOS pstopdf명령을 사용하여 EPS 파일을 PDF로 변환합니다.

#!/bin/zsh

FILES=$(find "/Users/Ben/Pictures/Stock Illustrations" -type f)

for f in "$FILES"
do
   echo "$f"
   pstopdf "$f"
done

echo "$f"pstopdf모든 파일의 올바른 목록을 생성하지만 그 자체에서 겉보기에 로 시작하는 두 번째 파일 목록을 얻지만 File name too long: /Users/Ben/Pictures/Stock Illustrations/Flock wallpaper.eps나머지 파일은 올바르게 나열됩니다.

그러나 이 pstopdf명령은 PDF 파일을 생성하지 않습니다.

** 각 명령이 파일 이름 목록을 생성한다는 것을 알기 위해 echo및 명령을 주석 처리해 보았습니다 .pstopdf

터미널에서 실행 하면 pstopdf <file.eps>CLI에서 어떤 출력도 얻지 못하지만(예: 파일 이름이 나열되지 않음) 파일이 처리되고 PDF 파일이 생성됩니다.

감히 명령 xargs에서 사용할 수 있다고 말씀드리지만 find, 특히 여러 명령과 기타 논리에 대한 옵션을 제공하고 읽기 더 쉽기 때문에 매개 변수가 있는 루프의 구조화된 접근 방식을 선호합니다.

여기에도 비슷한 질문이 있습니다.for..in을 실행하고 터치하면 "파일 이름이 너무 깁니다"라는 메시지가 나타납니다.

그러나 대답이 어떻게 적용되는지 이해하지 못합니다. "또는 하나씩 터치하세요"(제가 원하는 것)라고 되어 있지만 그렇게 하면 다음과 같습니다.

FILES=/Users/Ben/Pictures/Stock\ Illustrations/*

"해당 파일이나 디렉터리가 없습니다"라는 메시지가 나타납니다.

답변1

FILES=$(find "/Users/Ben/Pictures/Stock Illustrations" -type f)
for f in "$FILES"

링크된 게시물에 표시된 것처럼 $FILES여기에는 모든 파일 이름이 포함된 문자열이 있습니다. 파일이 충분하면 단일 파일 이름이 너무 길어집니다. 이름이 몇 개뿐인 경우 이름에 개행 문자가 포함된 파일에 액세스하려고 시도하게 됩니다.

find여기서는 자신을 부르는 것이 더 좋습니다 pstopf.

$ find "/Users/Ben/Pictures/Stock Illustrations" -type f -print -exec pstopdf {} \;

find 출력에 쉘 루프를 사용하려면 다음을 수행해야 합니다(Bash에서는 zsh에 대해 언급하지 않았습니다).

set -f      # disable globbing
IFS=$'\n'   # set IFS to just the newline (Bash/ksh/zsh, not POSIX)
files=$(find "/Users/Ben/Pictures/Stock Illustrations" -type f)
for f in $files; do
    echo "$f"
    pstopdf "$f"
done

아니면 find ... -print0 | while IFS= read -r -d '' f; do ...; doneBash에서 사용하세요.

또는 for f in "/Users/Ben/Pictures/Stock Illustrations"/**/*; do ...Bash(사용 shopt -s globstar), ksh 또는 zsh에서(세부 사항은 쉘마다 다소 다릅니다.

두 쉘 솔루션 모두 개행 문자가 포함된 파일 이름에 문제가 있습니다. 여러분에게는 그런 문제가 없기를 바라지만, 불행하게도 개행 문자는 허용됩니다.

답변2

FILES=$(find "/Users/Ben/Pictures/Stock Illustrations" -type f)

는 스칼라 변수 할당을 위한 구문(zsh 또는 기타 Korn 유사 쉘)이므로 $FILESa에 대해 하나의 값만 얻습니다. 이는 a의 전체 출력입니다 find.

여기서는 다음을 원할 것입니다.

files=( ${(0)"$(find "/Users/Ben/Pictures/Stock Illustrations" -type f -print0)"} )

$files발견된 각 파일을 요소로 하는 배열이 되기를 원하는 경우 find. find0으로 구분된 목록을 제공하고 0매개변수 확장 플래그를 사용하여 이를 s로 분할 해야 합니다 0. 이는 파일 경로에 나타날 수 없는 유일한 바이트 값이기 때문입니다.

하지만 여기서는 glob이 동일한 작업을 수행할 수 있으므로 find그럴 필요가 없습니다 .zsh

files=( "/Users/Ben/Pictures/Stock Illustrations"/**/*(ND.) )

재귀 **/*와일드카드 및 .와 동일합니다 -type f.

이를 반복하려면 다음이 필요합니다.

for f in $files; do
  print -r -- $f
  pstopdf $f
done

또는:

for f ($files) {
  print -r -- $f
  pstopdf $f
}

"$files"배열의 요소를 첫 번째 문자 $IFS( ksh 와 동일 )와 "${files[*]}"연결 하므로 이는 원하는 것이 아닙니다. zsh 에서 $files인용되지 않은 루프를 사용하여 배열의 null이 아닌 요소를 반복합니다 . "${files[@]}"모든 요소를 ​​반복하지만 배열에 빈 요소가 포함되지 않음이 보장되므로 여기서는 차이가 없습니다.

관련 정보