私はしばしばこれを使用してtee /proc/self/fd/2
stdoutとstderrに何かを表示し、stdoutへのすべての出力を維持しながらstdoutをキャプチャします。
たとえば、次のようになりますdo.sh
。
STD_OUT_STR=$(CMD ARGS ... 2>&1 | tee /proc/self/fd/2)
# handle STD_OUT_STR ...
...
これは非常にうまく機能します。
例えば、
./do.sh
デフォルトでは、次のように動作します。
bash -c 'echo hi | tee /proc/self/fd/2'
出力
hi
hi
しかしある日、私はそれを実行しsudo -u A_USER ./do.sh
ましたが失敗しました。
sudo -u A_USER ./do.sh'
デフォルトでは、次のように実行されます。
sudo -u A_USER bash -c 'echo hi | tee /proc/self/fd/2'
出力
tee: /proc/self/fd/2: Permission denied
hi
これまでは、次の回避策に従う必要があります。
sudo -u A_USER bash -c 'echo hi | tee >(cat >&2)'
私はこれがセキュリティ上の理由であることを理解しています。現在、ユーザーの pty は他のユーザーと共有されません。
sudo -u A_USER
プロセスにそのptyへのアクセスを許可するオプションがあるかどうか疑問に思います。
編集:do.shスクリプトに入れる必要があります。つまり、do.shの外にtee /proc/self/fd/2
入れることができないので役に立ちません。tee /proc/self/fd/2
sudo -u A_USER bash -c '...' | tee ...
答え1
sudo -u A_USER bash -c 'cmd | tee /dev/fd/2'
または:
sudo -u A_USER sh -c 'cmd | tee /dev/fd/2'
bashに関連する内容がないので、システムで動作します。外のLinuxやシグウィン。
ただし、ほとんどのシステムでは、オープンは/dev/fd/x
LinuxまたはCygwinと同じでdup(x)
あり、そのファイル記述子で開かれたファイルを指す「魔法の」シンボリックリンクであるため、ファイルを開くことはまったく同じではありません。>&x
sh
/dev/fd/x
/proc/self/fd/x
dup()
あなたの場合のように、書き込みのために開く権限がないファイルでfd 2が開いたり、ソケットでまったく開くことができない可能性があります(通常はsystemd
stderrがソケットによって開始されたプロセスjournald
)。
書き込み権限を持つ通常のファイルでも、そのファイルを最初から開いて切り取るため、間違っているか間違っていますtee /proc/self/fd/2
。tee /dev/fd/2
Eventee -a /proc/self/fd/2
は間違っています(実際は良いですが)。切り捨てが多すぎてファイルの最後で書き込みが完了するため、stderrが別の方法で開いている場合にのみ機能します。追加モデル。
たとえば、次のようになります。
(
echo test | tee -a /proc/self/fd/2
echo hi >&2
) 2> file
$ cat file
hi
t
出力はを介して記録さhi
れます。test
tee
Linux / Cygwinでの/dev/fd/x
/ /proc/self/fd/x
(または/dev/stdout
、/dev/stderr
)の使用は、そのfdが見つからないファイル(パイプやttyデバイスなど)で開かれている場合にのみ許可されますが、その場合でもここでこれらの権限の問題などの問題が発生する可能性があります。
シェルtee >(cat >&2)
はシェルをパイプで開いているどこかに変換し、パイプはユーザーがパイプtee /proc/self/fd/somefd
にsomefd
書き込んで作成したため、権限の問題はありませんが、bashシェルでこれを行うことはまだ間違っています。特にそうではないbashのようなものです。その過程をお待ちくださいcat
。
後ろに:
(bash -c 'echo test | tee >(cat>&2)'; echo hi >&2) 2> file
時には以下file
が含まれる場合もあります。
hi
tee
以前は最初の項目をbash
返し、cat
正常に作成して出力test
しecho
たためです。hi
ここでは、ファイルの代わりに複数のファイル記述子を使用する代わりに、次のようにzsh
使用できます。bash
tee
sudo -u A_USER zsh -c 'echo hi >&1 >&2'
fd(ここでは1 / stdout)が出力のために複数回リダイレクトされると、サービスを実行する内部プロセスにつながるパイプにリダイレクトされます。
sudo -u A_USER zsh -c 'echo hi | tee >(cat >&2)'
これは上記のbash警告なしで機能しますが、zshには機能が組み込まれているため、これらのtee
警告は必要ありません。cat
zsh
シェルから呼び出す場合は、USER_Aの代わりに呼び出すユーザーに内部提供を完了させることができます。
sudo -u A_USER sh -c 'echo hi' >&1 >&2
Linux/Cygwinで比較します。
sudo -u A_USER sh -c 'echo hi' | tee -a /dev/fd/2
それ自体より
sudo -u A_USER sh -c 'echo hi' | tee /dev/fd/2
(ライセンスの問題も解決しましたが)上記の理由によるものです。
権限の問題を解決するために stderr をパイプに変換するソリューションは、sh
(プロセス置換を使用できません) + を使用して手動で実行することです.tee
sudo sh -c '
{
{
cmd |
tee /dev/fd/2
} 2>&1 >&3 3>&- |
cat >&2 3>&-
} 3>&1'
内部コマンドグループ内では、stderrはcat
共有パイプになりますが、stderrをそのままにすることcmd
もできますcmd
。
sudo sh -c '
{
{
cmd 3>&- |
tee /dev/fd/3
} 3>&1 >&4 4>&- |
cat >&2 4>&-
} 4>&1'
cmd | tee >(cat >&2)
ここでcat
適切な待機が与えられたにもかかわらず、これはあなたの状況に近いです。
答え2
ただそのまま走ってくださいtee
。
次のコマンドを検討してください。
$ sudo -u A_USER bash -c 'ls -l *.txt 2>&1'
標準出力にテキスト行を送信します。
tee
他のユーザーとして実行する必要はありません。この行を持って自分のように処理します。sudo
後でパイプラインでこれらの権限が本当に必要な場合は、もう一度呼び出してください。
$ sudo -u A_USER bash -c 'ls -l *.txt 2>&1' | tee /proc/self/fd/2 | awk '{sum += $5} END {print sum}'
問題が発生した場合、スクリプトは常にファイルシステムに書き込んでから、他のプロセスのテキストファイルに書き込むことができますcat
。tail -f
テキストジェネレータは常に利用可能です。 標準バッファ 必要に応じて行バッファリングを調整し、結果をすぐに表示できます。