shopt globの設定やtcshに似た設定の組み合わせはありますか?

shopt globの設定やtcshに似た設定の組み合わせはありますか?

長い間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ファイル名拡張子に関連する唯一のオプションはdotglobfailglobおよびであり、そのどれも(単独でも組み合わせでも)正確に望む作業を実行できないようです。良い考えのように聞こえるので残念です。nocaseglobnullglob

私の提案は、failglob次のような不要なコマンドを避けるためにインタラクティブセッションで設定することです。

mv -r file1 file2 dir1 dir2 destination-*-dir

file1、 と が一致せずに設定されている場合、 と がfile2そのdir1項目に移動されます。dir2destination-*-dirnullglob

一方、シェルスクリプトを作成するときは、ファイル名拡張にのみ依存するのは良い考えではありません。そのような拡張が存在するか、どの拡張が必要かを常に確認することをお勧めします。

私の言葉は、こうしないでください:

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が、実際にはディレクトリです。

おすすめ記事