私は次の行を含むこのスクリプトを書いています。
ls -lrt /dir1/dir2/filename*.txt | tail -1 | awk '{print $9}' | read variable
私が望むのは、一致するものがない場合はif文を使用せずにスクリプトを終了することです。
答え1
このコマンドを書く方法
この特定の操作にはパイプラインは必要ありません。
zshから:
a=(/dir1/dir2/filename*.txt(Nom[1]))
if ((! #a)); then
echo >&2 "No file matches /dir1/dir2/filename*.txt"
exit 2
fi
variable=$a[1]
あるいは、globが一致しない場合は、自動的にスクリプトを終了します。
set -e
a=(/dir1/dir2/filename*.txt(om[1]))
variable=$a[1]
他のシェルには最新のファイルを見つける機能が組み込まれていません。ファイル名に改行文字以外の印刷可能文字のみが含まれている場合、呼び出しはls
合理的ですが、オプションを渡さなかった名前を-l
除くすべての文字を解析します。これは不必要に複雑で壊れやすい(特に空白割り込み)。また、sortの最後の項目-t
を取得するよりも高速なsortの最初の項目を取得します-tr
。直接方法:
variable=$(ls -td /dir1/dir2/filename*.txt 2>/dev/null | head -n 1)
if [ -z "$variable" ]; then
echo >&2 "No file matches /dir1/dir2/filename*.txt"
exit 2
fi
処理パイプライン
パイプの左側が失敗した場合(つまり、ゼロ以外の状態で終了するか、シグナルによって終了した場合)、スクリプトを中断するには、ksh93とbashでオプションを設定し、pipefail
パイプ状態をゼロ以外にすることができます。
set -e -o pipefail
somecommand | filter
echo "somecommand succeeded"
または
set -o pipefail
if ! somecommand | filter; then
echo >&2 "somecommand or filter failed"
exit 2
fi
Zshのオプションはありませんが、pipefail
配列内のパイプラインの各コンポーネントのステータスコードを取得できますpipestatus
。
somecommand | filter
if ((pipestatus[1])); then
echo >&2 "somecommand failed"
exit 2
fi
他のシェルでは、パイプの状態は右側のコマンドの状態です。左のコマンドの状態を検索する直接的な方法はありません。バラより終了状態を別のプロセスにパイプにインポートするいくつかの可能な解決策。
filter
の完全な出力を読む必要があります。それ以外の場合は、死んだときに何が起こるのかをsomecommand
処理する必要があります。somecommand
信号パイプライン。
somecommand
終了状態ではなく出力を生成するかどうかに応じてアクションを実行するには、次のようにします。ifne
~からJoey Hessのmoreutils。ほとんどのシステムでは、デフォルトでこれらのユーティリティはインストールされていません。
答え2
{ ls -lrt /dir1/dir2/filename*.txt ||
kill $$
} | tail -1 |
awk '{print $9}' |
read variable
あなた自身になりなさいkill
。時々、シェルは私がこれを行うときに少し文句を言うかもしれませんが、私がこれを行うと、シェルは不平をさえしないことがわかりましたkill -PIPE $$
。
または、戻りコードと残りの部分を具体的に指定するには、次の手順を実行します。
trap 'echo some error >&2; exit 1' USR1 $and_or_other_signals
{ ls ... || kill -USR1 $$; } |...
残りは..おそらく別の方法でしょう..?
touch ~/"a n\$ew file
in 'my home
directory"
v=$(ls -1rdt ~/* || kill -PIPE $$; echo /)
v=${v%?/*}; v=${v##*/}
printf '<%s>' ~/"$v"
出力
</home/mikeserv/a n$ew file
in 'my home
directory>
これにより、含まれる文字に関係なく、すべてのディレクトリで最後に変更されたファイルの名前を取得できます。<
>
変数の始まりと終わりを示し、後にスペースが含まれていないことを示すために使用されます。そしてこのecho
ビットははい末尾の空白が残っています。
これは確かにパイプを無効にし、ls
ゼロ以外の値が返された場合(たとえば、コマンドライン引数が存在しない場合)、スクリプト化されたシェルを終了し続けます。
並べ替えの順序を変更せずに同じことができますが、少しトリッキーで、簡単に実行するにはターゲットディレクトリに変更する必要があります。
touch ~/"a n\$ew file
in 'my home
directory"
v=$(cd ~; ls -dtm ./* || kill -PIPE $$)
v=${v#*/}; v=${v%%,?./*}
printf '<%s>' ~/"$v"
出力
</home/mikeserv/a n$ew file
in 'my home
directory>
私が考えるのにかなり移植性があると思われる別のアプローチは次のとおりです。
set /[d]ir1/dir2/filename*.txt
[ -z "${1##/\[*}" ] && exit 1
while [ -n "$2" ]
do [ "$1" -nt "$2" ] &&
set "$@" "$1"
shift; done; v=$1
printf %s\\n "$1" "$v"