추가 파일 설명자를 언제 사용 하시겠습니까? write to it exec 3>&- # close fd

파일 설명자를 만들고 출력을 리디렉션 할 수 있다는 것을 알고 있습니다. 예 :

exec 3<> /tmp/foo # open fd 3.
echo a >&3 # write to it
exec 3>&- # close fd 3.

그러나 파일 디스크립터없이 동일한 작업을 수행 할 수 있습니다.

FILE=/tmp/foo
echo a > "$FILE"

추가 파일 설명자를 사용해야하는 좋은 예를 찾고 있습니다.



답변

대부분의 명령에는 단일 입력 채널 (표준 입력, 파일 디스크립터 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

관심있는 다른 예 :

그리고 더 많은 예를 들어 :

추신 : 이것은 fd 3을 통한 경로 재 지정을 사용하는 사이트 에서 가장 많이 게시 된 게시물 의 저자가 보낸 놀라운 질문입니다 !


답변

다음은 여분의 FD를 bash 스크립트 대화 제어로 사용하는 예입니다.

#!/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"

답변

명명 된 파이프 (fifos)와 관련하여 추가 파일 디스크립터를 사용하면 비 블로킹 파이핑 동작을 사용할 수 있습니다.

(
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

참조 : 명명 된 파이프가 스크립트에서 조기에 종료됩니까?


답변

추가 파일 디스크립터는 변수에서 stdout을 잡으려고하지만 여전히 bash 스크립트 사용자 인터페이스와 같이 화면에 쓰려고 할 때 유용합니다.

arg1 string to echo
arg2 flag 0,1 print or not print to 3rd fd stdout descriptor
function ecko3 {
if [ "$2" -eq 1 ]; then
    exec 3>$(tty)
    echo -en "$1" | tee >(cat - >&3)
    exec 3>&-
else
    echo -en "$1"
fi
}

답변

추가 파일 디스크립터를 사용할 때의 또 다른 시나리오는 다음과 같습니다 (Bash에서).

명령 행 매개 변수의 쉘 스크립트 비밀번호 보안

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

답변

예 : flock을 사용하여 파일 잠금과 함께 스크립트를 직렬로 실행

한 가지 예는 파일 잠금을 사용하여 스크립트가 시스템 전체에서 강제로 실행되도록하는 것입니다. 같은 종류의 두 스크립트가 같은 파일에서 작동하지 않게하려는 경우에 유용합니다. 그렇지 않으면 두 스크립트가 서로 간섭하여 데이터가 손상 될 수 있습니다.

#exit if any command returns a non-zero exit code (like flock when it fails to lock)
set -e

#open file descriptor 3 for writing
exec 3> /tmp/file.lock

#create an exclusive lock on the file using file descriptor 3
#exit if lock could not be obtained
flock -n 3

#execute serial code

#remove the file while the lock is still obtained
rm -f /tmp/file.lock

#close the open file handle which releases the file lock and disk space
exec 3>&-

잠금 및 잠금 해제를 정의하여 기능적으로 무리 사용

이 잠금 / 잠금 해제 논리를 재사용 가능한 기능으로 랩핑 할 수도 있습니다. 다음 trap셸 내장 은 스크립트가 종료 될 때 파일 오류를 자동으로 해제합니다 (오류 또는 성공). trap파일 잠금을 정리하는 데 도움이됩니다. 경로 /tmp/file.lock는 여러 스크립트가 잠글 수 있도록 하드 코딩 된 경로 여야합니다.

# obtain a file lock and automatically unlock it when the script exits
function lock() {
  exec 3> /tmp/file.lock
  flock -n 3 && trap unlock EXIT
}

# release the file lock so another program can obtain the lock
function unlock() {
  # only delete if the file descriptor 3 is open
  if { >&3 ; } &> /dev/null; then
    rm -f /tmp/file.lock
  fi
  #close the file handle which releases the file lock
  exec 3>&-
}

unlock위 의 논리는 잠금이 해제되기 전에 파일을 삭제하는 것입니다. 이런 식으로 잠금 파일을 정리합니다. 파일이 삭제되었으므로이 프로그램의 다른 인스턴스가 파일 잠금을 얻을 수 있습니다.

스크립트에서 잠금 및 잠금 해제 기능 사용

다음 예제와 같이 스크립트에서 사용할 수 있습니다.

#exit if any command returns a non-zero exit code (like flock when it fails to lock)
set -e

#try to lock (else exit because of non-zero exit code)
lock

#system-wide serial locked code

unlock

#non-serial code

코드가 잠길 때까지 기다리려면 다음과 같이 스크립트를 조정할 수 있습니다.

set -e

#wait for lock to be successfully obtained
while ! lock 2> /dev/null; do
  sleep .1
done

#system-wide serial locked code

unlock

#non-serial code

답변

구체적인 예로서, 방금 하위 명령의 타이밍 정보가 필요한 스크립트를 작성했습니다. 추가 파일 설명자를 사용하면 time하위 명령의 stdout 또는 stderr를 중단하지 않고 명령의 stderr 을 캡처 할 수있었습니다 .

(time ls -9 2>&3) 3>&2 2> time.txt

이것이하는 것은 point ls의 stderr에서 fd 3, fd 3에서 스크립트의 stderr, point time의 stderr를 파일로 지정하는 것입니다. 스크립트가 실행될 때, stdout 및 stderr는 부속 명령과 동일하며 평소와 같이 경로 재 지정 될 수 있습니다. time의 출력 만 파일로 리디렉션됩니다.

$ echo '(time ls my-example-script.sh missing-file 2>&3) 3>&2 2> time.txt' > my-example-script.sh
$ chmod +x my-example-script.sh
$ ./my-example-script.sh
ls: missing-file: No such file or directory
my-example-script.sh
$ ./my-example-script.sh > /dev/null
ls: missing-file: No such file or directory
$ ./my-example-script.sh 2> /dev/null
my-example-script.sh
$ cat time.txt

real    0m0.002s
user    0m0.001s
sys 0m0.001s