単純なファイルループ - 「ファイル名が長すぎます」

単純なファイルループ - 「ファイル名が長すぎます」

私は最も基本的なタスク、つまり特定のフォルダ内のすべてのファイルに対して1つ以上のコマンドを実行しようとしています。

この場合、macOSpstopdfコマンドを使用して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すべてのファイルの正しいリストを生成しますが、それ自体が一見で始まる2番目のファイルのリストを取得しますが、残りのファイルは正しくリストされます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に対して1つの値のみを取得します。これはaのフル出力ですfind

ここでは、次のようになります。

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

$files見つかった各ファイルを要素とする配列になりたい場合findfindゼロで区切られたリストを提供し、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[@]}"すべての要素を繰り返しますが、配列に空の要素が含まれていないことが保証されるため、ここでは違いはありません。

関連情報