문자열을 반환하고 리디렉션 및 출력을 이해합니다.

문자열을 반환하고 리디렉션 및 출력을 이해합니다.

터미널에 여러 줄을 인쇄해야 하는 bash 함수에서 문자열을 선택적으로 출력하기 위해 리디렉션을 사용하는 방법을 알아내려고 합니다. 나는 답을 찾았다StackOverflow에 대한 질문. 아래 코드는 작동합니다. 그러나 나는 방법이나 이유를 이해하지 못합니다.

#!/bin/bash

exec 3>&1

returnString()
{
    exec 4>&1 >&3
    local s=$1
    s=${s:="some default string"}
    echo "writing to stdout"
    echo "writing to stderr" >&2
    exec >&4-
    echo "$s"
}

my_string=$(returnString "$*")
echo "my_string:  [$my_string]"

stdout나는 fd3이 처음 으로 리디렉션된다는 것을 알고 있습니다 . 그런 다음 fd4도 마찬가지입니다. 1은 3을 가리키며 기본적으로 자신을 가리킵니다. 그러나 이것이 터미널에 인쇄되는 내용에 어떤 영향을 미칠까요? 이 출력이 에는 표시되지 않지만 $my_stringfd4를 제거한 후 마지막 출력에는 표시되는 이유는 무엇입니까?

fd4에 명시적으로 전송된 것이 없기 때문에 fd4가 어떤 것과 관련이 있는지 이해하지 못합니다.

답변1

위에서 보여준 솔루션은 일반적인 솔루션이며 많은 경우를 포괄합니다. 문제가 있다는 것을 알지 못하는 한 YAGNI(필요하지 않음) 자세를 취하고 선택한 행을 /dev/tty로 리디렉션할 수 있습니다.

이를 방지하려면 현재 발생하고 있는 파일 설명자(fd) 저글링을 이해해야 합니다.

3>&1함수가 호출 컨텍스트의 표준 출력으로 출력할 수 있도록 호출 컨텍스트의 표준 출력을 "저장 단위"에 복사합니다 . 이 경우에는 /dev/tty입니다. 이 함수는 ${} 대체 서브셸에 속하는 stdout을 사용하여 호출된다는 점을 기억하세요.

exec 4>&1함수의 표준 출력인 fd1의 복사본을 만듭니다 . fd4는 함수 시작 시 표준 출력의 유지 단위로 사용됩니다. >&3함수/서브쉘의 표준 출력을 호출자의 표준 출력으로 설정합니다 . 따라서 모든 출력은 호출자의 표준 출력으로 전송됩니다. UNTIL은 마지막으로 >&4-저장된 표준 출력을 시작 위치로 다시 이동하여 마지막 echo "$s"표준 출력이 함수(및 하위 쉘)의 표준 출력에 포함될 수 있도록 합니다.

우와!

and 는 and 로 더 명확하게 작성할 >&3수도 있습니다 .>&4-1>&31>&4-

리디렉션에 관한 매뉴얼 섹션에서는 bash모든 세부 사항과 용어를 설명합니다. 나는 {name} 형식을 사용하여 실제로 숫자를 단어로 바꿀 수 있다는 사실을 알고 매우 기뻤습니다.

"파일 설명자 번호로 시작될 수 있는 각 리디렉션은 {varname} 형식의 단어로 시작할 수 있습니다. 이 경우 >&- 및 <&-를 제외한 각 리디렉션 연산자에 대해 10보다 큰 쉘 A 파일 설명자는 다음과 같습니다. varname에 할당됩니다. >&- 또는 <&- 앞에 {varname}이 오면 varname의 값은 닫힐 파일 설명자를 정의합니다.

나는 이것을 테스트하지는 않았지만 다음과 같이 코딩할 수 있다고 제안합니다.

#!/bin/bash

exec {caller_stdio}>&1

returnString() {
  exec {func_stdio}>&1 1>&{caller_stdio}
  local s=$1
  s=${s:="some default string"}
  echo "writing to stdout"
  echo "writing to stderr" >&2
  exec 1>&{func_stdio}-
  echo "$s"
}

my_string=$(returnString "$*")
echo "my_string:  [$my_string]"

답변2

exec 3>&1

fd3는 지금이다반복하다fd 1 (귀하의 예에서는 터미널). 매뉴얼 페이지에 명시되어 있듯이 이는 fd 1과 fd 3이 동일한 파일이나 장치를 참조하기 위해 상호 교환적으로 사용될 수 있음을 의미합니다.

쉘에서 복제하는 주요 목적은 나중에 복원할 수 있도록 fd의 복사본을 저장하는 것입니다.

my_string=$(returnString "$*")

Bash가 의 평가로부터 표준 출력을 얻기 위해 returnString "$*",관로그리고 포크를 들고 아이가 소리쳤어요듀프 2도착하다이동하다파이프의 쓰기 끝(이 예에서는 fd 5이지만 다를 수 있음)을 fd 1로 지정합니다.

exec 4>&1 >&3

리디렉션은 왼쪽에서 오른쪽으로 평가됩니다. fd 4는 파이프 끝의 반복으로 설정됩니다. 그런 다음 fd 1은 터미널을 참조하는 fd의 복사본으로 설정됩니다.

echo "writing to stdout"

터미널인 fd 1로 에코됩니다.

exec >&4-

그러면 fd 4가 fd 1로 이동됩니다(즉, dup2 실행). fd 1은 이제 파이프의 끝입니다.

echo "$s"

에코는 파이프 끝에 도달합니다. 궁극적으로 상위 쉘은 파이프의 다른 쪽 끝에서 이 값을 읽고 다음과 같이 사용합니다.$(returnString "$*")

관련 정보