長い間tcshユーザーを使用してから新しいbashユーザーに切り替えようとしています(遅すぎます)。私は定期的にtcshで多くのforeachループを書いているので、代わりにbashのforループ構文を学びましたが、一致しないglobパターンがリテラル文字列としてループを通して渡されるのを見て驚きました。リテラル文字列をスキップして検索できるように、この動作を変更する方法を探していますshopt -s nullglob
。私の理解は、理論的にはこれがtcshの仕組みと同じでなければならないということです。しかし、今日私は違いを見つけました。これを行うと、ls ../*.doesnotmatch
結果は現在のディレクトリの内容のリストです。具体的には次のようにします。
大きな打撃:
$ shopt -s nullglob
$ ls ../*.sam
extractSplitReads_BwaMem extractSplitReads_BwaMem.xml
$ shopt -u nullglob
$ ls ../*.sam
ls: ../*.sam: No such file or directory
親ディレクトリのどれも一致せず*.sam
、特に現在のディレクトリと一致します。最初は本当に混乱していましたが、グローバルモードが消えて引数を提供していないかのようにコマンドが実行されていることに気づきました。たとえば、次のようになります。
$ ls
そのため、FAILGlobのみを設定し、nullglobを使用してフェイルグローブを設定しようとしましたが、フェイルグローブが設定されるとすぐに一致するパターンがあるかどうかにかかわらず、一致しないglobパターンがあればコマンドは終了します。
大きな打撃:
$ shopt -s failglob
$ shopt -s nullglob
$ ls ../vis*/*.xml
../visualization/LAJ.xml
$ ls ../vis*/*.xml ../*.sam
bash: no match: ../*.sam
$ ls ../{vis*/*.xml,*.sam}
bash: no match: ../*.sam
tcsh を使用すると、すべての glob が一致する項目に減り、一致する項目がないと glob エラーが発生します。
tcsh:
$ ls ../vis*/*.xml ../*.sam
../visualization/LAJ.xml
$ ls ../{vis*/*.xml,*.sam}
../visualization/LAJ.xml
$ ls ../*.sam
ls: No match.
私はshopt設定を見ましたが、この動作を達成する方法が見つかりませんでした。私は何を逃したことがありませんか? Bashやtcshに加えて、tcshなどのグローバル変数を処理できる別の最新のシェルはありますか?私は一致するものがある場合はnullglobアクションを望んでいますが、一致するものがない場合はFailglobアクションが必要です。これはtcshがどのように機能するかのようです。
ベストアンサー1
shopt
ファイル名拡張子に関連する唯一のオプションはdotglob
、failglob
およびであり、そのどれも(単独でも組み合わせでも)正確に望む作業を実行できないようです。良い考えのように聞こえるので残念です。nocaseglob
nullglob
私の提案は、failglob
次のような不要なコマンドを避けるためにインタラクティブセッションで設定することです。
mv -r file1 file2 dir1 dir2 destination-*-dir
file1
、 と が一致せずに設定されている場合、 と がfile2
そのdir1
項目に移動されます。dir2
destination-*-dir
nullglob
一方、シェルスクリプトを作成するときは、ファイル名拡張にのみ依存するのは良い考えではありません。そのような拡張が存在するか、どの拡張が必要かを常に確認することをお勧めします。
私の言葉は、こうしないでください:
rm -- *.jpg *.txt
次のようにすることをお勧めします。
for file in *.jpg *.txt; do
if [ -f "${file}" ]; then
rm -- "${file}"
fi
done
# Or this (non-POSIX, as it uses an array)
for file in *.jpg *.txt; do
if [ -f "${file}" ]; then
files_to_delete+=( "${file}" )
fi
done
if [ "${#files_to_delete[@]}" -gt 0 ]; then
rm -- "${files_to_delete[@]}"
fi
これにより、一部のファイルが一致しても安全です*.txt
が、実際にはディレクトリです。