ファイル記述子を作成し、出力をそのファイルにリダイレクトできることを知っています。例えば
exec 3<> /tmp/foo # open fd 3.
echo a >&3 # write to it
exec 3>&- # close fd 3.
ただし、ファイル記述子がなくても同じことができます。
FILE=/tmp/foo
echo a > "$FILE"
追加のファイル記述子を使用する必要がある場合の良い例を探しています。
答え1
ほとんどのコマンドは、入力チャンネル(標準入力、ファイル記述子0)と出力チャンネル(標準出力、ファイル記述子1)を持っているか、独自に開く複数のファイルで動作します(したがってファイル名を渡します)。 (これは通常ユーザーにフィルタリングする標準エラー(fd 2)に追加されます。)ただし、時には複数のソースまたは複数のターゲットでフィルタとして機能する単一のコマンドを使用するのが便利な場合があります。たとえば、次は、ファイル内の奇数行と偶数行を区別する単純なスクリプトです。
while IFS= read -r line; do
printf '%s\n' "$line"
if IFS= read -r line; then printf '%s\n' "$line" >&3; fi
done >odd.txt 3>even.txt
では、奇数行と偶数行に異なるフィルタを適用したいとしましょう(しかし、再結合はしません。これは他の問題になる可能性があり、通常はシェルでは実行できません)。シェルでは、あるコマンドの標準出力を別のコマンドにのみパイプできます。他のファイル記述子をパイプするには、まずfd 1にリダイレクトする必要があります。
{ while … done | odd-filter >filtered-odd.txt; } 3>&1 | even-filter >filtered-even.txt
もう一つの簡単なユースケースはコマンドのエラー出力フィルタリング。
exec M>&N
スクリプトの残りの部分に対して、あるファイル記述子を別のファイル記述子にリダイレクトします(または別のコマンドがファイル記述子を再変更するまで)。exec M>&N
との間には機能がいくつか重複していますsomecommand M>&N
。このexec
形式は入れ子にする必要がないため、より強力です。
exec 8<&0 9>&1
exec >output12
command1
exec <input23
command2
exec >&9
command3
exec <&8
興味があるかもしれない他の例:
- スクリプトで「3>&1 1>&2 2>&3」は何をしますか?(stdoutをstderrに置き換えます)
- ファイル記述子とシェルスクリプト
- パイプバッファはどれくらい大きいですか?
- Bashスクリプトは、コマンドが正しく実行されているかどうかをテストします。
より多くの例があります:
- フラグ付きの質問
io-redirection
- フラグ付きの質問
file-descriptors
- このサイトで例を検索してください。内部にデータブラウザ(Stack Exchange データベースの公開読み取り専用コピー)
PS これは著者が提起した驚くべき質問です。fd 3を介したリダイレクトを使用するサイトで最も承認された投稿!
答え2
以下は、bashスクリプトチャットコントロールとして追加のFDを使用する例です。
#!/bin/bash
log() {
echo $* >&3
}
info() {
echo $* >&4
}
err() {
echo $* >&2
}
debug() {
echo $* >&5
}
VERBOSE=1
while [[ $# -gt 0 ]]; do
ARG=$1
shift
case $ARG in
"-vv")
VERBOSE=3
;;
"-v")
VERBOSE=2
;;
"-q")
VERBOSE=0
;;
# More flags
*)
echo -n
# Linear args
;;
esac
done
for i in 1 2 3; do
fd=$(expr 2 + $i)
if [[ $VERBOSE -ge $i ]]; then
eval "exec $fd>&1"
else
eval "exec $fd> /dev/null"
fi
done
err "This will _always_ show up."
log "This is normally displayed, but can be prevented with -q"
info "This will only show up if -v is passed"
debug "This will show up for -vv"
答え3
名前付きパイプのコンテキストでは、非ブロックパイプの動作は追加のファイル記述子を使用して達成されます。
(
rm -f fifo
mkfifo fifo
exec 3<fifo # open fifo for reading
trap "exit" 1 2 3 15
exec cat fifo | nl
) &
bpid=$!
(
exec 3>fifo # open fifo for writing
trap "exit" 1 2 3 15
while true;
do
echo "blah" > fifo
done
)
#kill -TERM $bpid
答え4
これは、追加のファイル記述子を使用することが適切に見える別のケースです。
コマンドラインパラメータのシェルスクリプトパスワードセキュリティ
env -i bash --norc # clean up environment
set +o history
read -s -p "Enter your password: " passwd
exec 3<<<"$passwd"
mycommand <&3 # cat /dev/stdin in mycommand