2つの可能なパスがあり、Linuxシステムのディレクトリとファイルを一覧表示したいとします。
/some/path1/
/some/path2/
次のようにすると、tcsh
終了コードの1つ以上が存在する場合は終了コードが得られます。0
path1
path2
ls -d /some/{path1,path2}/*
ただし、で同じことを行うと、終了コードとそのコードが存在しないというメッセージが表示さbash
れます(path1が存在しないパスの場合)。2
stderr
path1
この状況でどのようにこれbash
を行うことができますか?tcsh
1つ以上のパスが存在する場合に返すように要求できるスイッチはありますか?両方がない場合、ゼロ以外のコードが返されると予想します。ls
0
tcsh
答え1
あなたの質問に対するほとんどの回答は、次のアドレスで解決されました。nullglobがデフォルトではないのはなぜですか?。
覚えておくべきことの1つは次のとおりです。
ls -d /some/{path1,path2}/*
csh
// tcsh
/ zsh
/(しかし以下ではありません)以下を使用bash
して:ksh
fish
ls -d /some/path1/* /some/path2/*
サポート拡大を行う場合今後(いいえの一部として/some/pathx/*
)glob拡張。これは、別の引数として渡される一致するファイルのリストにこれらのパターンをシェルから拡張することですls
。
bash
、ksh
主にコピーは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
zsh
Kornに似たシェルで、cshに似たシェルです。一致しない glob がそのまま渡されるという点で Bourne シェルの欠陥は発生しませんが、デフォルトはこれより厳しく失敗したcsh
すべての glob は致命的なエラーとして扱われます。したがって、zsh
デフォルトでは、一方/some/path1/*
または/some/path2/*
両方が一致しない場合、コマンドは中断されます。 option²を使用して、シェルでbash
同様の動作を有効にできますfailglob
。
これは、動作をより予測可能で一貫したものにしますが、複数のglob拡張をコマンドに渡し、globの1つが成功するたびに失敗したくない場合に問題が発生する可能性があります。ただし、cshnullglob
cshと同様の動作(または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
的にls
literalというファイルが一覧表示される可能性があり/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
引数リストが渡されないとエラーが発生します.
。ただし、nullglob
glob拡張を使用して配列に保存し、ls
配列メンバーが空でない場合にのみパラメータとして呼び出すことができます。
(
shopt -s nullglob
files=( /some/path1/* /some/path2/* )
if (( ${#files[@]} > 0 )); then
ls -d -- "${files[@]}"
else
echo >&2 No match
exit 2
fi
)
グローバルに有効にする代わりに、zsh
glob修飾子(kshに触発されたがまだコピーされていません)を使用してnullglob
globごとに有効にし、再配列の代わりに匿名関数を使用できます。(N)
~(N)
bash
() {
(( $# > 0 )) && ls -d -- "$@"
} /some/path1/*(N) /some/path2/*(N)
シェルは、globが(配列割り当てのために)使用されるか、何らかの方法で動作しない限り、エラーを引き起こす失敗したglobのようにfish
動作します。zsh
for
set
count
nullglob
また、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 sh
emulate ksh
set +o nomatch
² グローバルな不一致があるときに正確にどのような動作がキャンセルされるかは、大きな違いがあります。どのようなfish
振る舞いがより合理的でbash -O failglob
最悪なのかもしれません。
答え2
ただ読んでくださいスティーブンの答え。
bash
これは、何も一致しない地球を処理する方法が原因で発生します。で観察したのと同じ動作を得るには、tcsh
bashのオプションを有効にする必要があります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