シェルの代わりに「コマンド内部」でワイルドカードを拡張

シェルの代わりに「コマンド内部」でワイルドカードを拡張

(これは複雑な環境で最も簡単な作業例です。)

dファイルを含むディレクトリがあります1.txt 2.txt 3.txt 4.wav。私の現在のディレクトリは別の場所にあります。

ls d報告し1.txt 2.txt 3.txt 4.wavてください。

しかし、それが私が望むすべてだ1.txt 2.txt 3.txtからですls d/*.txt

ただし、これはシェルがファイルを表示する前に拡張するため、d/すべてのファイル名の前に次のものが追加されます。d/1.txt d/2.txt d/3.txt*ls

私が望むものを得るために、代わりに新しいシェルを作成すること1.txt 2.txt 3.txtもできます。出力をフィルタリングするためのより良い方法、より薄く、落とし穴やエッジケースにあまり脆弱な方法はありますか?ls d | grep txtls d/*.txt | xargs basename -a(cd d; ls *.txt)ls

答え1

そしてzsh

printf '%s\n' d/*.txt(:t)

:tcsh履歴修飾子に似ていますが、glob修飾子では次のようになります。ファイル名。

返品:

files=(d/*.txt)
printf '%s\n' $files:t

Bourneに似た他のシェルでは、いつでも次のことができます。

(cd d && printf '%s\n' *.txt)

新しいシェルをフォークするのではなく、サブシェル環境を作成することに注意してください。ほとんどのシェル実装では、サブシェル環境はサブプロセスをフォークすることによって達成されますが、新しいシェルはその中で実行されません(新しいシェルではありませんが、新しいプロセスで同じシェルがフォークされます)。また、サブシェルの最後のコマンドが外部コマンドである場合、ほとんどのシェル(ではありませんbash)は追加のプロセスを作成しないため、実行中のプロセスの総数はサブシェル環境がない場合と同じです。

ksh93サブシェルをフォークしません。サブシェルを終了するときは、サブシェルで行われた変更を元に戻すことでこれを行います。したがって、(printf組み込みの場合)追加の(cd d && printf '%s\n' *.txt)プロセスは分岐しません。

また、lsファイルとコンテンツ引数として渡されるディレクトリです。ここでlsシェルから提供された名前だけを印刷する場合は必要ありませんが、こだわりの場合はそのlsオプション-dを渡してディレクトリの内容を一覧表示しないようにする必要があります。

(cd d && ls -d -- *.txt)

答え2

あなたが要求したことを行う最も簡単な方法は次のとおりです。

$ ( cd d; ls *.txt )
1.txt  2.txt  3.txt

これはサブシェル内で発生するため、( ... )ディレクトリの変更は永続的ではなく、これら2つのコマンドを実行した場合にのみ有効です。

より強力なバージョンは次のとおりです。

$ ( cd d && ls -d -- *.txt )
1.txt  2.txt  3.txt

lsディレクトリの変更が成功しないと、その内容は実行されず、ディレクトリのls内容の代わりにリストされ、名前がダッシュで始まるファイルはオプションとして提供されません。


位置パラメータ(など)$1を変更してもよい場合は、この方法も比較的簡単です。$2

$ set d/*.txt
$ for f do printf '%s\n' "${f#d/}"; done
1.txt
2.txt
3.txt

これはPOSIXシェルで動作します。

$ dash -c 'set d/*.txt; for f do printf "%s\n" "${f#d/}"; done'
1.txt
2.txt
3.txt

GNU findを使用できます-printf

$ find d -maxdepth 1 -iname "*.txt" -printf "%f\n" | sort
1.txt
2.txt
3.txt

しかし、これは十分に複雑になりました。申し訳ありません。私が知っている限り、もう「簡単な」解決策はありません。

関連情報