GNU/Linux >> Linux の 問題 >  >> Linux

スペースを含むファイルのリストを反復処理する

非常に簡単な解決策もあります:bash グロビングに頼る

$ mkdir test
$ cd test
$ touch "stupid file1"
$ touch "stupid file2"
$ touch "stupid   file 3"
$ ls
stupid   file 3  stupid file1     stupid file2
$ for file in *; do echo "file: '${file}'"; done
file: 'stupid   file 3'
file: 'stupid file1'
file: 'stupid file2'

この動作がデフォルトの動作であるかどうかはわかりませんが、shopt に特別な設定が表示されないため、「安全」である必要があると言うことに注意してください (osx と ubuntu でテスト済み)。


これを実現するには、いくつかの実行可能な方法があります。

元のバージョンに厳密に固執したい場合は、次の方法で行うことができます:

getlist() {
        IFS=$'\n'
        for file in $(find . -iname 'foo*') ; do
                printf 'File found: %s\n' "$file"
        done
}

ファイル名にリテラルの改行が含まれている場合でも、これは失敗しますが、スペースで区切られることはありません。

ただし、IFS をいじる必要はありません。これを行うための私の好みの方法は次のとおりです:

getlist() {
    while IFS= read -d $'\0' -r file ; do
            printf 'File found: %s\n' "$file"
    done < <(find . -iname 'foo*' -print0)
}

< <(command) が見つかった場合 構文に慣れていない場合は、プロセス置換について読む必要があります。 for file in $(find ...) に対するこれの利点 スペース、改行、その他の文字を含むファイルが正しく処理されることです。 find のため、これは機能します -print0null を使用します (別名 \0 ) を各ファイル名のターミネータとして使用し、改行とは異なり、null はファイル名の有効な文字ではありません。

ほぼ同等のバージョンに対するこれの利点

getlist() {
        find . -iname 'foo*' -print0 | while read -d $'\0' -r file ; do
                printf 'File found: %s\n' "$file"
        done
}

while ループの本体での変数の割り当ては保持されます。つまり、while にパイプすると、 上記のように while の本体 あなたが望むものではないかもしれないサブシェルにあります.

find ... -print0 | xargs -0に対するプロセス置換バージョンの利点 最小です:xargs ファイルに対して 1 行を印刷するか、1 つの操作を実行するだけであれば、バージョンは問題ありませんが、複数のステップを実行する必要がある場合は、ループ バージョンの方が簡単です。

編集 :これは、この問題を解決するためのさまざまな試行の違いを理解できるように、優れたテスト スクリプトです。

#!/usr/bin/env bash

dir=/tmp/getlist.test/
mkdir -p "$dir"
cd "$dir"

touch       'file not starting foo' foo foobar barfoo 'foo with spaces'\
    'foo with'$'\n'newline 'foo with trailing whitespace      '

# while with process substitution, null terminated, empty IFS
getlist0() {
    while IFS= read -d $'\0' -r file ; do
            printf 'File found: '"'%s'"'\n' "$file"
    done < <(find . -iname 'foo*' -print0)
}

# while with process substitution, null terminated, default IFS
getlist1() {
    while read -d $'\0' -r file ; do
            printf 'File found: '"'%s'"'\n' "$file"
    done < <(find . -iname 'foo*' -print0)
}

# pipe to while, newline terminated
getlist2() {
    find . -iname 'foo*' | while read -r file ; do
            printf 'File found: '"'%s'"'\n' "$file"
    done
}

# pipe to while, null terminated
getlist3() {
    find . -iname 'foo*' -print0 | while read -d $'\0' -r file ; do
            printf 'File found: '"'%s'"'\n' "$file"
    done
}

# for loop over subshell results, newline terminated, default IFS
getlist4() {
    for file in "$(find . -iname 'foo*')" ; do
            printf 'File found: '"'%s'"'\n' "$file"
    done
}

# for loop over subshell results, newline terminated, newline IFS
getlist5() {
    IFS=$'\n'
    for file in $(find . -iname 'foo*') ; do
            printf 'File found: '"'%s'"'\n' "$file"
    done
}


# see how they run
for n in {0..5} ; do
    printf '\n\ngetlist%d:\n' $n
    eval getlist$n
done

rm -rf "$dir"

単語ベースの反復を行ベースの反復に置き換えることができます:

find . -iname "foo*" | while read f
do
    # ... loop body
done

Linux
  1. findコマンドを使用してLinux上のファイルとディレクトリを検索します

  2. ファイルを検索して tar (スペースを含む)

  3. Unixで人間が読めるファイルを見つける

  1. ディレクトリ内のファイル サイズがゼロ (0) バイトのすべてのファイルを再帰的に検索する方法

  2. ファイルのリストを検索から除外する

  3. ACL が設定されたファイルを検索

  1. Linux で絶対パスを使用してファイルのリストを生成するにはどうすればよいですか?

  2. 検索ですべてのグラフィック イメージ ファイルを一覧表示しますか?

  3. バイナリファイルを除くすべてのサブディレクトリ内のすべての通常ファイルを一覧表示/検索します