서브쉘 없이 쉘 함수의 출력 캡처

서브쉘 없이 쉘 함수의 출력 캡처

내 컴퓨터에 (Ruby 버전 관리자)를 설치 했는데 rbenv다음과 같이 작동합니다.

$ rbenv local
2.3.1

에 쓰기표준 출력내 로컬 버전의 Ruby입니다. 이 버전을 구출하고 다른 경우에 재사용할 수 있도록 변수에 선언하고 싶습니다.

$ declare -r RUBY_DEFINED_VERSION=$(rbenv local)
$ echo Using ruby version $RUBY_DEFINED_VERSION
Using ruby version 2.3.1

효과가있다!

하지만 사용하고 싶지 않아요서브쉘작업을 완료합니다( $()또는 사용 ``). 나도 똑같이 사용하고 싶다껍데기나는tmp작업을 완료하는 데 필요한 파일입니다.

이를 수행할 수 있는 방법이 있습니까?

노트: declare -r필수 사항은 아니며 간단할 수 있습니다 var=FOOBAR.

답변1

해킹이 있지만 루프를 통해 실행해야 한다면 의미가 있다고 생각합니다.

다음과 같이 열 수 있습니다 cat coproc.coproc CAT { cat; }

그러면 cat백그라운드에서 명령이 실행되고 두 개의 환경 변수( CAT_PID및 ) 가 설정됩니다 CAT. 이 변수는 사용된 파일 설명자(파이프)를 (순서대로) 포함 하는 CAT배열입니다 .STDOUTSTDINcat

&${CAT[1]}따라서 표시되는 모든 항목 에 출력을 쓸 수 STDIN있으며 내장 명령을 사용하여 read읽을 변수를 cat으로 설정할 ${CAT[0]}수 있습니다 STDOUT.

예는 다음과 같습니다.

coproc CAT { cat; }
echo 123 >&${CAT[1]}
read myvar <&${CAT[0]}

테스트하려면:

echo $myvar
123

사용 후에는 고양이를 차단하는 것을 잊지 마세요. 프로세스를 종료하면 이를 수행할 수 있습니다.

kill $CAT_PID

이는 성능 튜닝에 큰 영향을 미칩니다.

업데이트: 구분된 문자열을 bash구현했습니다 null. 그래서 이진 데이터를 다룰 때는 read정말 까다롭습니다 . 한 번에 한 바이트씩 읽을 수 있으며 null은 변수의 빈 문자열이 LC_ALL=C read -r -n1 -d $'\0'됩니다 .${REPLY}

답변2

Bash를 사용하면 다음과 같은 작업도 수행할 수 있습니다.

read a < <(echo hello)
echo "$a"

또는 다음과 같습니다:

shopt -s lastpipe
echo hello | read a
shopt -u lastpipe
echo "$a"

하지만 여전히 Ruby를 실행할 하위 프로세스를 시작해야 하므로 무엇을 피하려고 하는지 잘 모르겠습니다...

답변3

Linux에서 bash5.1(또는 zsh) 이전 버전을 사용하는 경우 다음을 수행할 수 있습니다.

{
  chmod u+w /dev/fd/3 # only needed in bash 5.0
  rbenv local > /dev/fd/3
  IFS= read -rd '' -u 3 variable
} 3<<< ''

비록 숨겨져 있지만 여기에서는 문서별 또는 여기에서는 문자열과 같은 임시 파일을 사용합니다.

bash5.1 일반 임시 파일 대신 파이프를 사용하십시오(적어도 herefile/herestring의 내용이 파이프 버퍼에 들어갈 만큼 충분히 작은 경우). 이를 사용하면 언제든지 임시 파일을 수동으로 만들 수 있습니다.

tmpfile=$(mktemp) || exit
{
  rm -f -- "$tmpfile"
  rbenv local >&3
  IFS= read -rd '' -u4 variable
} 3> "$tmpfile" 4< "$tmpfile"

<<<<<(예 : 쉘이 종료될 때 스크립트가 종료되거나 남겨질 위험을 최소화하려면 tmpfile을 일찍 제거하십시오 ).rbenv

출력이 파이프에 들어갈 수 있는 것보다 적은 데이터(일반적으로 64KiB) 인 경우 rbenv여전히 Linux 및 Linux에서만 임시 파일 대신 파이프를 사용할 수 있습니다.

{
  rbenv local > /dev/fd/3
  IFS= read -rd '' -u 3 variable
} 3< <(:)

ksh93또는 최신 버전 의 경우 mksh하위 쉘을 시작하지 않는 명령 대체 형식을 사용하십시오.

variable=${
  rbenv local
}

이 버전은 현재 bash 및 zsh 개발 버전에서도 사용할 수 있습니다.

이 방법과 달리 IFS= read -rd ''출력에서 ​​후행 줄 바꿈을 제거합니다(일반 명령 대체와 마찬가지로).

이를 달성하기 위해 ksh93의 현재(2024년 기준) 버전은 내부적으로 사전 삭제된 임시 파일( /dev/shm내 Debian 시스템에서), mksh( /tmp내 시스템에서), zsh-dev를 사용하며 파일만 나중에 삭제됩니다. bash-dev를 삭제하고 익명으로 만들기메모리지원되는 곳에는 임시 파일이 있고, 지원되지 않는 곳에는 미리 삭제된 임시 파일이 있습니다 /tmp.

이전 버전에서는 자동으로 삭제된 임시 파일을 가져오기 위해 프로세스 대체 형식을 zsh활용했습니다 (여기서는 익명 함수에 대한 매개변수로 전달됨).=(...)

() { rbenv local > $1; IFS= read -rd '' variable <$1; } =()

1 그러나 zsh에 관한 한 ${ cmd }현재 이 작업을 수행할지 아니면 따옴표 없이만 수행할지에 대한 논쟁이 있습니다.

관련 정보