回答:
同等のPOSIXはありません。リダイレクトexec
は、フォークではなくでのみ実行できます。パイプはフォークを必要とし、シェルは子が完了するのを待ちます。
1つの解決策は、すべてのコードを関数に入れることです。
all_my_code () {
…
}
{ all_my_code |
logger --priority user.notice --tag "$(basename "$0")"; } 2>&1 |
logger --priority user.error --tag "$(basename "$0")"
(これにより、ロガーのstdoutインスタンスからstderrインスタンスへのエラーもログに記録されます。より多くのファイル記述子シャッフルでこれを回避できます。)
logger
プロセスがまだ実行されている場合でも親シェルを終了する場合&
は、logger
呼び出しの最後に置きます。
{ all_my_code |
logger --priority user.notice --tag "$(basename "$0")" & } 2>&1 |
logger --priority user.error --tag "$(basename "$0")" &
または、名前付きパイプを使用できます。
pipe_dir=$(mktemp -d)
mkfifo "$pipe_dir/out" "$pipe_dir/err"
<"$pipe_dir/out" logger --priority user.notice --tag "$(basename "$0")" &
<"$pipe_dir/err" logger --priority user.error --tag "$(basename "$0")" &
exec >"$pipe_dir/out" 2>"$pipe_dir/err"
…
rm -r "$pipe_dir"
logger
それぞれに同じ入力を渡します。
_log()( x=0
while [ -e "${TMPDIR:=/tmp}/$$.$((x+=1))" ]
do continue; done &&
mkfifo -- "$TMPDIR/$$.$x" &&
printf %s\\n "$TMPDIR/$$.$x" || exit
exec >&- >/dev/null
{ rm -- "$TMPDIR/$$.$x"
logger --priority user."$1" --tag "${0##*/}"
} <"$TMPDIR/$$.$x" &
) <&- </dev/null
あなたはそれを次のように使うことができるはずです:
exec >"$(_log notice)" 2>"$(_log error)"
mktemp
コマンドを使用するバージョンは次のとおりです。
_log()( p=
mkfifo "${p:=$(mktemp -u)}" &&
printf %s "$p" &&
exec <&- >&- <>/dev/null >&0 &&
{ rm "$p"
logger --priority user."$1" --tag "${0##*/}"
} <"$p" &
)
...ほとんど同じmktemp
ですが、ファイル名を選択できる点が異なります。これが機能するのは、プロセスの置換が魔法ではなく、コマンドの置換と非常によく似ているためです。コマンド置換のように展開内で実行されるコマンドの値で展開を置き換えるのではなく、プロセス置換は、出力が見つかるファイルシステムリンクの名前に置き換えます。
POSIXシェルはそのようなものへの直接の帰結を提供しませんが、それをエミュレートすることは非常に簡単に行われます。必要なのは、ファイルを作成し、その名前をコマンド置換から標準に出力し、同じ実行のバックグラウンドでそのファイルに出力するコマンドを実行することだけです。これで、その拡張の値にリダイレクトできます- プロセス置換の場合とまったく同じです。そして、POSIXシェルはもちろん、必要なすべてのツールを提供します-必要なのは、自分に合った方法でそれらを使用することだけです。
上記のバージョンはどちらも、作成または使用するパイプへのファイルシステムリンクを破棄してから、それらを使用する前に確実に破棄します。これは、事後にクリーンアップが必要ないことを意味します。さらに重要なことに、それらのストリームは最初にそれらを開くプロセスでのみ使用できます。したがって、それらのファイルシステムリンクは、ロギングアクティビティをスヌープ/ハイジャックする手段として使用できません。ファイルシステムにfsリンクを残すことは、潜在的なセキュリティホールです。
別の方法は、それをラップすることです。スクリプト内から実行できます。
x=${x##*[!0-9]*}
_log(){
logger --priority user."$1" --tag "${0##*/}"
} 2>/dev/null >&2
cd ../"$PPID.$x" 2>/dev/null &&
trap 'rm -rf -- "${TMPDIR:-/tmp}/$PPID.$x"' 0 ||
{ until cd -- "${TMPDIR:=/tmp}/$$.$x"
do mkdir -- "$TMPDIR/$$.$((x+=1))"
done &&
x=$x "$0" "$@" | _log notice
exit
} 2>&1 | _log error
これにより、スクリプトがまだ呼び出されていない場合に基本的にスクリプトがそれ自体を呼び出し、一時的に作業ディレクトリを起動することができます。
mktemp
その他の非標準コマンドを使用したい場合は、次のようになります_log()( p=; mkfifo "${p:=$(mktemp -u)}"; printf %s "$p"; exec <&- >&- <>/dev/null >&0; { rm "$p"; logger --priority user."$1" --tag "${0##*/}"; } <"$p" &)
。私は、完全に移植可能なコマンド言語を使って、自分の例外を除いて、あらゆる方法でそれを書きました。また、basename
あまり有用なユーティリティではありません。"${0##*/}"
より堅牢で高速です。
.xprofile
持って実行されますsh
。
zsh
マルチOS対応です。最初の部分については:{ this; can\'t; happen; before; } < this
。それは役に立ちますか?