選ぶ

選ぶ

次のファイル名が与えられた場合:

$ ls -1
file
file name
otherfile

bashそれ自体は埋め込まれた空白に対して非常にうまく機能します。

$ for file in *; do echo "$file"; done
file
file name
otherfile
$ select file in *; do echo "$file"; done
1) file
2) file name
3) otherfile
#?

しかし、すべてのファイルを処理したくない、または厳密$PWDfind。公称スペースも処理します。

$ find -type f -name file\*
./file
./file name
./directory/file
./directory/file name

whspace安全バージョンを作成しようとしています。これスクリプトレットは出力を取得してfind次にレンダリングしますselect

$ select file in $(find -type f -name file); do echo $file; break; done
1) ./file
2) ./directory/file

ただし、これを行うとファイル名にスペースがあります。

$ select file in $(find -type f -name file\*); do echo $file; break; done
1) ./file        3) name          5) ./directory/file
2) ./file        4) ./directory/file  6) name

通常、私はこの問題を周囲を乱すことで解決しますIFS。しかし:

$ IFS=$'\n' select file in $(find -type f -name file\*); do echo $file; break; done
-bash: syntax error near unexpected token `do'
$ IFS='\n' select file in $(find -type f -name file\*); do echo $file; break; done
-bash: syntax error near unexpected token `do'

この問題に対する解決策は何ですか?

ベストアンサー1

埋め込み改行文字ではなく、スペースやタブのみを処理する必要がある場合は、次のようにmapfile(またはその同義語)を使用して配列を読み取ることができます。readarray

$ ls -1
file
other file
somefile

それから

$ IFS= mapfile -t files < <(find . -type f)
$ select f in "${files[@]}"; do ls "$f"; break; done
1) ./file
2) ./somefile
3) ./other file
#? 3
./other file

もしあなたならする改行を処理する必要があり、バージョンが null で区切られた1 をbash提供する場合は、これを に変更できます。それ以外の場合は、ループを使用してnullで区切られた出力からその配列をアセンブルします。mapfileIFS= mapfile -t -d '' files < <(find . -type f -print0)findread

$ touch $'filename\nwith\nnewlines'
$ 
$ files=()
$ while IFS= read -r -d '' f; do files+=("$f"); done < <(find . -type f -print0)
$ 
$ select f in "${files[@]}"; do ls "$f"; break; done
1) ./file
2) ./somefile
3) ./other file
4) ./filename
with
newlines
#? 4
./filename?with?newlines

1 このオプションは-dバージョン 4.4 iircmapfileで追加されました。bash

おすすめ記事