ワイルドカード拡張で最初の一致を取得するには?

ワイルドカード拡張で最初の一致を取得するには?

BashやZshなどのシェルは、パターンに一致する引数の数を使用してワイルドカードを引数に拡張します。

$ echo *.txt
1.txt 2.txt 3.txt

しかし、すべての一致ではなく最初の一致のみを返したい場合はどうすればよいですか?

$ echo *.txt
1.txt

シェル固有のソリューションは気に入らませんが、ファイル名のスペースを処理できるソリューションが必要です。

ベストアンサー1

Bashで安定した方法は、配列に展開して最初の要素のみを出力することです。

pattern="*.txt"
files=( $pattern )
echo "${files[0]}"  # printf is safer!

echo $files(欠落しているインデックスを[0]として扱うこともできます。)

これは、ファイル名を拡張するときにスペース/タブ/改行やその他のメタ文字を安全に処理します。有効なロケール設定によっては、「最初」の意味が変わる場合があります。

bashを使用して対話的にこれを実行することもできます。完全な機能:

_echo() {
    local cur=${COMP_WORDS[COMP_CWORD]}   # string to expand

    if compgen -G "$cur*" > /dev/null; then
        local files=( ${cur:+$cur*} )   # don't expand empty input as *
        [ ${#files} -ge 1 ] && COMPREPLY=( "${files[0]}" )
    fi
}
complete -o bashdefault -F _echo echo

これは_echo関数をechoコマンドの完全な引数にバインドします(通常の完成をオーバーライドします)。上記のコードには追加の「*」が追加されており、部分的なファイル名でタブを押すと正しいことが起こることを願っています。

コードは少し説明することはできませんが、()を設定または想定するのではなく、nullglobglobをいくつかの一致に拡張してから安全に配列に展開し、最後に参照が信頼できるようにCOMPREPLYを設定できることを確認してください。shopt -s nullglobcompgen -G

あなたはできます部分的にbashを使用してこれを行うことはできますが(プログラミング方式でグローバルに拡張)、標準compgen -G出力に引用符を使用せずに出力するため、強力ではありません。

いつものように、完了は非常に心配です。これは、環境変数を含む他のものの完了を中止します(_bash_def_completion()関数を参照)。ここ基本動作シミュレーションの詳細については、参照)。

compgen完成機能の外部でも使用できます。

files=( $(compgen -W "$pattern") )

1つの注目すべき点は、「〜」はglobではなく、$variablesや他の拡張と同様に、別の拡張ステップでbashによって処理されることです。compgen -Gファイル名のグロービングのみを実行しますが、compgen -Wbashのデフォルトの拡張子をすべて提供します(``および含む$())。-G同じではない-W はい安全な引用符(違いを説明できない)その目的-Wはタグを拡張することで、ファイルが存在しなくても「a」を「a」に拡張することを意味するので、おそらく理想的ではありません。

これは理解しやすいが望ましくない副作用があるかもしれません。

_echo() {
    local cur=${COMP_WORDS[COMP_CWORD]}
    local files=( $(compgen -W "$cur") ) 
    printf -v COMPREPLY %q "${files[0]}"  
}

それから:

touch $'curious \n filename'

echo curious*tab

これらの値を安全に参照するために慎重に使用してくださいprintf %q

最後のオプションは、GNUユーティリティでゼロで区切られた出力を使用することです(参照:バッシュFAQ):

pattern="*.txt"
while IFS= read -r -d $'\0' filename; do 
    printf '%q' "$filename"; 
    break; 
done < <(find . -maxdepth 1 -name "$pattern" -printf "%f\0" | sort -z )

このオプションを使用すると、ソート順序をよりよく制御できますが(グローバルを拡張するときの順序はロケールによって異なり、大/小文字を折りたたむことも折りたたむLC_COLLATEこともできます)、このような小さな問題の場合はかなり大きなハンマーです。 )

おすすめ記事