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

おすすめ記事