複数のモードで「ls」を実行するときは、ゼロ以外の終了コードを使用しないでください。

複数のモードで「ls」を実行するときは、ゼロ以外の終了コードを使用しないでください。

2つの可能なパスがあり、Linuxシステムのディレクトリとファイルを一覧表示したいとします。

/some/path1/
/some/path2/

次のようにすると、tcsh終了コードの1つ以上が存在する場合は終了コードが得られます。0path1path2

ls -d /some/{path1,path2}/*

ただし、で同じことを行うと、終了コードとそのコードが存在しないというメッセージが表示さbashれます(path1が存在しないパスの場合)。2stderrpath1

この状況でどのようにこれbashを行うことができますか?tcsh1つ以上のパスが存在する場合に返すように要求できるスイッチはありますか?両方がない場合、ゼロ以外のコードが返されると予想します。ls0tcsh

答え1

あなたの質問に対するほとんどの回答は、次のアドレスで解決されました。nullglobがデフォルトではないのはなぜですか?

覚えておくべきことの1つは次のとおりです。

ls -d /some/{path1,path2}/*

csh// tcsh/ zsh/(しかし以下ではありません)以下を使用bashして:kshfish

ls -d /some/path1/* /some/path2/*

サポート拡大を行う場合今後(いいえの一部として/some/pathx/*)glob拡張。これは、別の引数として渡される一致するファイルのリストにこれらのパターンをシェルから拡張することですls

bashksh主にコピーはBourneシェルによって導入されたバグ機能を継承します。したがって、globパターンがどのファイルとも一致しない場合、コマンドの引数として効果的に渡されます。

したがって、これらのシェルで/some/path1/*1つ以上のファイルが一致し、/some/path2/*一致するファイルがない場合は、リテラルを引数として使用して呼び出されますls。ファイルが存在しないため、エラーが報告されます。-d/some/path1/file1/some/path1/file2/some/path2/*/some/path2/*ls

cshこの動作は、globがシェルではなく/etc/globヘルパーユーティリティ(ユーティリティにglobという名前を付ける)によって実行される以前のバージョンのUnixと似ています。ヘルパーはコマンドを呼び出す前にグローバル拡張を実行し、次のNo match場合にコマンドを実行せずにエラーを報告します。みんなglobパターンはどのファイルとも一致できません。それ以外の場合は、一致するグローブが1つ以上ある限り、一致しないすべてのグローブが削除されます。

したがって、上記の例では、csh/tcshまたは古いThompsonシェルとその/etc/globヘルパーを使用して呼び出しのみが実行され、ls成功する可能性が最も高くなります(検索可能な限り)。-d/some/path1/file1/some/path1/file2/some/path1

zshKornに似たシェルで、cshに似たシェルです。一致しない glob がそのまま渡されるという点で Bourne シェルの欠陥は発生しませんが、デフォルトはこれより厳しく失敗したcshすべての glob は致命的なエラーとして扱われます。したがって、zshデフォルトでは、一方/some/path1/*または/some/path2/*両方が一致しない場合、コマンドは中断されます。 option²を使用して、シェルでbash同様の動作を有効にできますfailglob

これは、動作をより予測可能で一貫したものにしますが、複数のglob拡張をコマンドに渡し、globの1つが成功するたびに失敗したくない場合に問題が発生する可能性があります。ただし、cshnullglobcshと同様の動作(またはemulate csh)を取得するためのオプションを設定できます。

これは匿名関数を使用してローカルで行うことができます。

() { set -o localoptions -o cshnullglob; ls -d /some/{path1,path2}/*; }

または単にサブシェルを使用してください:

(set -o cshnullglob; ls -d /some/{path1,path2}/*)

ただし、ここでは2つのglobを使用する代わりに、交互のglob演算子を使用してすべてのglobに一致する1つのglobを使用できます。

ls -d /some/(path1|path2)/*

ここでもできます:

ls -d /some/path[12]/*

では、置換を含むkshの拡張glob演算子のサブセットをサポートするようにbashのオプションをbash有効にできます。extglob

(shopt -s extglob; ls -d /some/@(path1|path2)/*)

Bourneシェルから継承されたバグ機能のためにglobがどのファイルとも一致しない場合は、そのまま渡され、/some/@(path1|path2)/*最終ls的にlsliteralというファイルが一覧表示される可能性があり/some/@(path1|path2)/*ます。failglob

(shopt -s extglob failglob; ls -d /some/@(path1|path2)/*)

nullglobまたは、オプション(bashからコピーzsh)を使用することもできます。みんな一致しない地球は空に拡張されます。しかし:

(shopt -s nullglob; ls -d /some/path1/* /some/path2/*)

コマンドの特別なケースでは、ls引数リストが渡されないとエラーが発生します.。ただし、nullglobglob拡張を使用して配列に保存し、ls配列メンバーが空でない場合にのみパラメータとして呼び出すことができます。

(
  shopt -s nullglob
  files=( /some/path1/* /some/path2/* )
  if (( ${#files[@]} > 0 )); then
    ls -d -- "${files[@]}"
  else
    echo >&2 No match
    exit 2
  fi
)

グローバルに有効にする代わりに、zshglob修飾子(kshに触発されたがまだコピーされていません)を使用してnullglobglobごとに有効にし、再配列の代わりに匿名関数を使用できます。(N)~(N)bash

() {
  (( $# > 0 )) && ls -d -- "$@"
} /some/path1/*(N) /some/path2/*(N)

シェルは、globが(配列割り当てのために)使用されるか、何らかの方法で動作しない限り、エラーを引き起こす失敗したglobのようにfish動作します。zshforsetcountnullglob

また、fish中括弧の拡張自体はワイルドカードではありませんが、ワイルドカードの一部として実行されます。または、中かっこ拡張がワイルドカードと結合されている場合は、少なくともコマンドを中断せずに1つ以上の要素を返すことができます。

したがってfish

ls -d /some/{path1,path2}/*

結局のように行動しますcsh

でも:

{ls,-d,/xx*}

不一致lsは失敗ではなく別の呼び出しを引き起こします(この場合の動作はcshとは異なります)。-d/xx*

とにかくファイルパスのみを一致させる場合はprint必要ありませんls。では、内蔵機能を使用して列ごとに印刷zshできます。print

print -rC3 /some/{path1,path2}/*(N)

awパスは3列に印刷されますr(ullglob glob修飾子と一致しないと何も印刷されませんN)。

代わりに、これら 2 つのディレクトリのいずれかに隠されていないファイルが 1 つ以上あるかどうかを確認するには、次の手順を実行します。

# bash
if (shopt -s nullglob; set -- /some/path1/* /some/path2/*; (($#))); then
   echo yes
else
   echo no
fi

または、次の機能を使用してください。

has_non_hidden_files() (
  shopt -s nullglob
  set -- "$1"/*
  (($#))
)
if has_non_hidden_files /some/path1 || has_non_hidden_files /some/path2
then
  echo yes
else
  echo no
fi
# zsh
if ()(($#)) /some/path1/*(N) /some/path2/*(N); then
  echo yes
else
  echo no
fi

または、次の機能を使用してください。

has_non_hidden_files() ()(($#)) $1/*(NY1)
if has_non_hidden_files /some/path1 || has_non_hidden_files /some/path2
then
  echo yes
else
  echo no
fi

Y1最初のファイルを見つけた後に停止する最適化で)

has_non_hidden_filesユーザーが読み取れないディレクトリ(ファイルがあるかどうかにかかわらず)については、(自動)falseを返します。では、zsh特殊変数を使用してこの状況を検出できます。$ERRNO


1 Bourne の動作(POSIX で指定)は、以下を実行しzshて有効にできます。emulate shemulate kshset +o nomatch

² グローバルな不一致があるときに正確にどのような動作がキャンセルされるかは、大きな違いがあります。どのようなfish振る舞いがより合理的でbash -O failglob最悪なのかもしれません。

答え2

ただ読んでくださいスティーブンの答え


bashこれは、何も一致しない地球を処理する方法が原因で発生します。で観察したのと同じ動作を得るには、tcshbashのオプションを有効にする必要がありますnulglob。からman bash

空のボール

設定されている場合、bashは、どのファイルとも一致しないパターン(上記のパス名の拡張を参照)を、自分ではなく空の文字列に拡張することを許可します。

有効にnullglobするとshopt -s nullglob、期待される動作が得られます。

$ ls
bar
$ ls {bar,foo}/*
ls: cannot access 'foo/*': No such file or directory
 bar/ff
$ echo $?
2


$ shopt -s nullglob 
$ ls {bar,foo}/*
bar/ff
$ echo $?
0

関連情報