11

bashを使用して、追加の診断メッセージを書き込むための新しい記述子を開こうとしています。stderrには、bashによって呼び出されたプログラムからの出力のみが含まれている必要があるため、stderrは使用しません。また、カスタム記述子をユーザーがリダイレクトできるようにしたい。

私はこれを試しました:

exec 3>/dev/tty
echo foo1
echo foo2 >&2
echo foo3 >&3

しかし、fd 3をリダイレクトしようとすると、出力はまだ端末に書き込まれます。

$ ./test.sh >/dev/null 2>/dev/null 3>/dev/null
foo3
4

5 に答える 5

9

最初に、親シェルがファイル記述子3を/ dev / nullに
設定します。次に、プログラムがファイル記述子3を/ dev / ttyに設定します
。したがって、症状はそれほど驚くべきものではありません。

編集:fd3が設定されているかどうかを確認できます。

if [[ ! -e /proc/$$/fd/3 ]]
then
    exec 3>/dev/tty
fi
于 2012-05-14T18:52:37.067 に答える
5

非常に単純です。親シェルがfd3をリダイレクトしていないtest.sh場合は、fd3をにリダイレクトし/dev/ttyます。

if ! { exec 0>&3; } 1>/dev/null 2>&1; then
   exec 3>/dev/tty
fi
echo foo1
echo foo2 >&2
echo foo3 >&3
于 2013-03-18T16:42:19.640 に答える
2

(Bash)シェルのみを使用してファイル記述子がすでに設定されているかどうかを確認する方法は次のとおりです。

(
# cf. "How to check if file descriptor exists?", 
# http://www.linuxmisc.com/12-unix-shell/b451b17da3906edb.htm

exec 3<<<hello

# open file descriptors get inherited by child processes, 
# so we can use a subshell to test for existence of fd 3
(exec 0>&3) 1>/dev/null 2>&1 && 
    { echo bash: fd exists; fdexists=true; } || 
    { echo bash: fd does NOT exists; fdexists=false; }

perl -e 'open(TMPOUT, ">&3") or die' 1>/dev/null 2>&1 && 
    echo perl: fd exists || echo perl: fd does NOT exist

${fdexists} && cat <&3
)
于 2013-02-23T12:30:32.027 に答える
1

アップデート

これを行うことができます。最も簡単な方法については、kaluyの回答を参照してください。

元の回答

答えは「できない」のようです。スクリプトで作成された記述子は、スクリプトを呼び出したシェルには適用されません。

誰かが興味を持っているなら、私はルビーを使ってそれを行う方法を理解しました。perlを使用した更新も参照してください。

begin
  out = IO.new(3, 'w')
rescue Errno::EBADF, ArgumentError
  out = File.open('/dev/tty', 'w')
end
p out.fileno
out.puts "hello world"

これは明らかにデーモンでは機能しないことに注意してください-ターミナルに接続されていません。

アップデート

ルビーが気に入らない場合は、ルビースクリプトからbashスクリプトを呼び出すだけです。出力の信頼性の高い配管には、open4 gem/libraryが必要です。

require 'open4'

# ... insert begin/rescue/end block from above

Open4.spawn('./out.sh', :out => out)

更新2

これは、少しのperlとほとんどのbashを使用する方法です。欠落しているperl実行可能ファイルもゼロ以外の終了コードを返すため、perlがシステムで正しく機能していることを確認する必要があります。

perl -e 'open(TMPOUT, ">&3") or die' 2>/dev/null
if [[ $? != 0 ]]; then
  echo "fd 3 wasn't open"
  exec 3>/dev/tty
else
  echo "fd 3 was open"
fi
echo foo1
echo foo2 >&2
echo foo3 >&3
于 2012-05-14T18:45:24.180 に答える
1

@Kelvin:これがあなたが要求した修正されたスクリプトです(そしていくつかのテスト)。

echo '
#!/bin/bash

# If test.sh is redirecting fd 3 to somewhere, fd 3 gets redirected to /dev/null;
# otherwise fd 3 gets redirected to /dev/tty.
#{ exec 0>&3; } 1>/dev/null 2>&1 && exec 3>&- || exec 3>/dev/tty
{ exec 0>&3; } 1>/dev/null 2>&1 && exec 3>/dev/null || exec 3>/dev/tty

echo foo1
echo foo2 >&2
echo foo3 >&3

' > test.sh

chmod +x test.sh

./test.sh
./test.sh 1>/dev/null
./test.sh 2>/dev/null
./test.sh 3>/dev/null
./test.sh 1>/dev/null 2>/dev/null
./test.sh 1>/dev/null 2>/dev/null 3>&-
./test.sh 1>/dev/null 2>/dev/null 3>/dev/null
./test.sh 1>/dev/null 2>/dev/null 3>/dev/tty

# fd 3 is opened for reading the Here String 'hello'
# test.sh should see that fd 3 has already been set by the environment
# man bash | less -Ip 'here string'
exec 3<<<hello
cat <&3
# If fd 3 is not explicitly closed, test.sh will determine fd 3 to be set.
#exec 3>&- 
./test.sh

exec 3<<<hello
./test.sh 3>&-
于 2013-03-13T16:41:04.607 に答える