あなたのシェルフラグメント:
- 標準出力 ( ) を、標準エラー ( ) が現在出力
1
されている場所に出力します。2
と
- 標準出力 ( ) が現在
2
出力されている場所に、標準エラー ( ) が出力されるようにします。1
2 回目の操作は必要ありません。
元の答え
さらに深刻なことに、標準エラーがファイルに出力される状態でコードが呼び出された場合、シェルの出力は同じファイルに出力されます。本当に元の標準出力と同じ場所に出力したい場合は、 でリダイレクトする前に元の標準出力を保持する必要がありますfreopen()
。次のようにします。
int fd1 = dup(FILENO_STDOUT);
...now do freopen...
dup2(fd1, FILENO_STDOUT);
close(fd1);
...now launch shell...without I/O redirection
修正された回答
シナリオを考えると:
- ログインシェルは、プログラム Program-A を実行するために使用されます (ソースがなく、
freopen()
標準出力を使用します)。
/bin/sh 1>&2 2>&1
Program-A は Program-B を実行します (これは、表記法を使用して対話型シェルを起動するシェル スクリプトです)。
また、インタラクティブ シェルの標準出力を元の標準出力に出力したい場合は、次のコードを使用してこれを行うことができます。
launch.sh
追加の I/O リダイレクトと環境変数を設定して Program-A を実行します。
set -x
fd -n 32
exec 3>&1
echo "$0: $@"
fd -n 32
FD_COPY_STDIN=3 exec ./Program-A "$@"
fd
プログラムは、開いているファイル記述子と閉じているファイル記述子を出力しo
ます-
。は、-n 32
「最初の 32 個のファイル記述子のステータスを出力」を指定します (デフォルトでは、考えられるすべてのファイル記述子を出力しますが、64 個のダッシュで構成される数百行は読むのが非常に退屈です)。
プログラム-A
変更不可能なプログラムをシミュレートするシェル スクリプト。標準出力をファイル ( standard.output
) に移動するように変更した後、Program-B を実行します。
set -x
echo "$0: $@"
# Simulate freopen("./standard.output", "w", stdout);
exec 1> ./standard.output
echo "$0: $@"
fd -n 32
exec ./Program-B "$@"
(必要に応じて、最後のものを削除して、終了exec
後に何かをエコーすることもできProgram-B
ます。)
プログラム-B
これは修正したスクリプトです — によって実行されるプログラムProgram-A
:
echo "$0: $@"
fd -n 32
exec 1>&${FD_COPY_STDOUT:-3}
exec 3>&- 2>&1
echo "$0: $@"
fd -n 32
exec ${SHELL} -i
(繰り返しますが、最終的なexec
ものを削除して、後でスクリプト内で別のことを行うことができます。)
この-i
オプションは、対話型シェルを呼び出します。2>&1
標準エラーを、標準出力と同じ場所にリダイレクトします。インタラクティブ シェルは、標準エラーでプロンプトを表示します (これも難しい方法であることがわかりましたが、以前にこの動作に遭遇したことがあります)。
実行例
コマンドはisodate
と同等date +'%Y-%m-%d %H:%M:%S'
です。マシン上の私の標準プロンプトosiris
はOsiris JL:
.
ファイルにリダイレクトされる標準エラーなし:
Osiris JL: ls
launch.sh Program-A Program-B
Osiris JL: bash launch.sh $(isodate)
+ fd -n 32
ooo-----------------------------
+ exec
+ echo 'launch.sh: 2014-05-20' 17:03:59
launch.sh: 2014-05-20 17:03:59
+ fd -n 32
oooo----------------------------
+ FD_COPY_STDIN=3
+ exec ./Program-A 2014-05-20 17:03:59
+ echo '/home/jleffler/soq/New/Program-A: 2014-05-20' 17:03:59
/home/jleffler/soq/New/Program-A: 2014-05-20 17:03:59
+ exec
+ echo '/home/jleffler/soq/New/Program-A: 2014-05-20' 17:03:59
+ fd -n 32
+ exec ./Program-B 2014-05-20 17:03:59
/home/jleffler/soq/New/Program-B: 2014-05-20 17:03:59
ooo-----------------------------
jleffler@osiris:~/soq/New$ ls -l
total 16
-rwxr----- 1 jleffler eng 100 May 20 17:02 launch.sh
-rwxr----- 1 jleffler eng 158 May 20 17:02 Program-A
-rwxr----- 1 jleffler eng 121 May 20 17:02 Program-B
-rw-r----- 1 jleffler eng 208 May 20 17:03 standard.output
jleffler@osiris:~/soq/New$ exit
exit
Osiris JL:
標準エラーがファイルにリダイレクトされる場合:
Osiris JL: bash launch.sh $(isodate) 2>standard.error
ooo-----------------------------
launch.sh: 2014-05-20 17:05:11
oooo----------------------------
/home/jleffler/soq/New/Program-A: 2014-05-20 17:05:11
/home/jleffler/soq/New/Program-B: 2014-05-20 17:05:11
ooo-----------------------------
jleffler@osiris:~/soq/New$ ls -l
total 20
-rwxr----- 1 jleffler eng 100 May 20 17:02 launch.sh
-rwxr----- 1 jleffler eng 158 May 20 17:02 Program-A
-rwxr----- 1 jleffler eng 121 May 20 17:02 Program-B
-rw-r----- 1 jleffler eng 343 May 20 17:05 standard.error
-rw-r----- 1 jleffler eng 208 May 20 17:05 standard.output
jleffler@osiris:~/soq/New$ exit
exit
Osiris JL: cat standard.error
+ fd -n 32
+ exec
+ echo 'launch.sh: 2014-05-20' 17:05:11
+ fd -n 32
+ FD_COPY_STDIN=3
+ exec ./Program-A 2014-05-20 17:05:11
+ echo '/home/jleffler/soq/New/Program-A: 2014-05-20' 17:05:11
+ exec
+ echo '/home/jleffler/soq/New/Program-A: 2014-05-20' 17:05:11
+ fd -n 32
+ exec ./Program-B 2014-05-20 17:05:11
Osiris JL: cat standard.output
/home/jleffler/soq/New/Program-A: 2014-05-20 17:05:11
oooo----------------------------
/home/jleffler/soq/New/Program-B: 2014-05-20 17:05:11
oooo----------------------------
Osiris JL: