web-dev-qa-db-ja.com

別のスクリプトで最後のシェルコマンドの終了コードを取得する

通知スクリプトを強化しようとしています。スクリプトの動作方法は、長時間実行されているシェルコマンドの背後に配置し、長時間実行されたスクリプトが終了した後、あらゆる種類の通知が呼び出されることです。

例えば:

sleep 100; my_notify

長時間実行されるスクリプトの終了コードを取得するのは良いことです。問題は、my_notifyを呼び出すと、$?変数にアクセスできない新しいプロセスが作成されることです。

比較する:

~ $: ls nonexisting_file; echo "exit code: $?"; echo "PPID: $PPID"
ls: nonexisting_file: No such file or directory
exit code: 1
PPID: 6203

vs.

~ $: ls nonexisting_file; my_notify      
ls: nonexisting_file: No such file or directory
exit code: 0
PPID: 6205

my_notifyスクリプトには次のものが含まれます。

#!/bin/sh
echo "exit code: $?"
echo "PPID: $PPID"

コマンドの構造をあまり変更せずに、前のコマンドの終了コードを取得する方法を探しています。 timeのように動作するように変更すると、 my_notify longrunning_command...私の問題は解決しますが、実際にはコマンドの最後にそれを追加することができ、この2番目の解決策の合併症を恐れています。

これを行うことはできますか、それともシェルの動作方法と根本的に互換性がありませんか?

私のシェルはzshですが、bashでも動作するようにしたいです。

36
sebastiangeiger

それを実現するには、実際にシェル関数を使用する必要があります。このような単純なスクリプトの場合、zshとbashの両方で動作させるのはかなり簡単です。以下をファイルに配置するだけです。

my_notify() {
  echo "exit code: $?"
  echo "PPID: $PPID"
}

次に、シェル起動ファイルからそのファイルを入手します。これは対話型シェル内から実行されるため、$ PPIDではなく$$を使用することもできます。

40
qqx

互換性がありません。 $?のみ現在のシェル内に存在します。サブプロセスで使用できるようにする場合は、環境変数にコピーする必要があります。

別の方法は、代わりに何らかの方法で使用するシェル関数を記述することです。

これを実装する1つの方法は、EOFタグとmy_notifyスクリプトを作成するマスタースクリプトを使用することです。


#!/bin/bash

if [ -f my_notify ] ; then
rm -rf my_notify
fi

if [ -f my_temp ] ; then
rm -rf my_temp
fi

retval=`ls non_existent_file &> /dev/null  ; echo $?`
ppid=$PPID
echo "retval=$retval" 
echo "ppid=$ppid" 
cat >> my_notify << 'EOF'
#!/bin/bash

echo "exit code: $retval"
echo " PPID =$ppid"
EOF

sh my_notify 

このスクリプトを目的に合わせて調整できます。

2
BIBS