programing

파이프에서 셸 변수로 값 읽기

firstcheck 2023. 4. 8. 20:52
반응형

파이프에서 셸 변수로 값 읽기

파이프로 연결된 stdin의 데이터를 처리하기 위해 bash를 호출하려고 합니다만, 잘 되지 않습니다.내 말은 다음 작업 중 하나가 아니라는 것입니다.

echo "hello world" | test=($(< /dev/stdin)); echo test=$test
test=

echo "hello world" | read test; echo test=$test
test=

echo "hello world" | test=`cat`; echo test=$test
test=

은 「」으로 해 .test=hello world붙여서 써보다."$test"그것도 효과가 없어요

사용하다

IFS= read var << EOF
$(foo)
EOF

속일 수 있다read이런 파이프에서 받아들이게 만들죠.

echo "hello world" | { read test; echo test=$test; }

또는 다음과 같은 함수를 쓸 수도 있습니다.

read_from_pipe() { read "$@" <&0; }

하지만 의미가 없습니다. !수할!!!!!!!!!!!!!!!!!!!파이프라인은 환경이 참조가 아닌 값으로 상속되는 하위 쉘을 생성할 수 있습니다. ★★★★★read이치노정의되어 있지 않습니다.

참고로 http://www.etalabs.net/sh_tricks.html은 본 셸의 이상성과 비호환성을 퇴치하기 위해 필요한 교묘한 컬렉션입니다.

많은 데이터를 읽고 각 행에서 개별적으로 작업하려면 다음과 같은 방법을 사용할 수 있습니다.

cat myFile | while read x ; do echo $x ; done

행을 여러 단어로 분할하려면 다음과 같이 x 대신 여러 변수를 사용할 수 있습니다.

cat myFile | while read x y ; do echo $y $x ; done

또는 다음과 같이 입력합니다.

while read x y ; do echo $y $x ; done < myFile

그러나 이러한 종류의 작업을 통해 매우 현명한 작업을 하고 싶다면 다음과 같은 작업을 수행할 수 있는 perl 등의 스크립트 언어를 사용하는 것이 좋습니다.

perl -ane 'print "$F[0]\n"' < myFile

perl(또는 이들 언어 중 하나)에는 상당히 가파른 학습 곡선이 있지만, 가장 단순한 스크립트 이외의 작업을 하고 싶다면 장기적으로 훨씬 더 쉬워질 것입니다.Perl Cookbook과 물론 Larry Wall 등의 Perl Programming Language를 추천합니다.

이것은 다른 옵션입니다.

$ read test < <(echo hello world)

$ echo $test
hello world

read파이프에서 읽을 수 없습니다(또는 파이프가 하위 셸을 생성하기 때문에 결과가 손실될 수 있습니다).단, Bash에서는 다음 문자열을 사용할 수 있습니다.

$ read a b c <<< $(echo 1 2 3)
$ echo $a $b $c
1 2 3

, @chepner의하십시오.lastpipe.

저는 Bash에 대해서는 잘 모릅니다만, 왜 이것이 제안되지 않았는지 궁금하네요.

stdin=$(cat)

echo "$stdin"

나에게 효과가 있다는 한 줄의 증거:

$ fortune | eval 'stdin=$(cat); echo "$stdin"'

bash4에는 4.2가 .lastpipe이 옵션을 사용하면 하위 셸이 아닌 현재 셸의 파이프라인에서 마지막 명령을 실행하여 코드가 작성된 대로 작동할 수 있습니다.

shopt -s lastpipe
echo "hello world" | read test; echo test=$test

PIPE 인수와 명령줄 인수 모두에서 데이터를 읽을 수 있는 스마트스크립트

#!/bin/bash
if [[ -p /dev/stdin ]]
    then
    PIPE=$(cat -)
    echo "PIPE=$PIPE"
fi
echo "ARGS=$@"

출력:

$ bash test arg1 arg2
ARGS=arg1 arg2

$ echo pipe_data1 | bash test arg1 arg2
PIPE=pipe_data1
ARGS=arg1 arg2

설명:스크립트가 파이프를 통해 데이터를 수신하면 /dev/stdin(또는 /proc/self/fd/0)은 파이프에 대한 심볼링크가 됩니다.

/proc/self/fd/0 -> pipe:[155938]

그렇지 않으면 현재 단말기를 가리킵니다.

/proc/self/fd/0 -> /dev/pts/5

★★[[ -p이치노

cat - 읽다stdin.

를 사용하는 cat -stdin 수 있기 if★★★★★★ 。

셸 명령에서 bash 변수로의 암묵적인 파이프 구문은 다음과 같습니다.

var=$(command)

또는

var=`command`

예제에서는 데이터를 아무 입력도 기대하지 않는 할당 문에 파이프하고 있습니다.

제 눈에는 stdin in bash를 읽는 가장 좋은 방법은 다음과 같습니다.또한 입력이 끝나기 전에 행에서 작업할 수 있습니다.

while read LINE; do
    echo $LINE
done < /dev/stdin

첫 번째 시도는 꽤 아슬아슬했다.이 변형은 기능합니다.

echo "hello world" | { test=$(< /dev/stdin); echo "test=$test"; };

출력은 다음과 같습니다.

test=hello 월드

테스트할 할당과 에코를 둘러싸려면 파이프 뒤에 중괄호가 필요합니다.

중괄호를 사용하지 않으면 테스트할 할당(파이프 다음)이 하나의 셸에 있고 에코 "test=$test"는 해당 할당을 모르는 별도의 셸에 있습니다.따라서 출력에 "test=hello world" 대신 "test="가 표시됩니다.

내가 속았으니 쪽지를 남기고 싶다.POSIX 호환성을 가지려면 오래된 sh 스크립트를 다시 써야 하기 때문에 이 스레드를 찾았습니다.이는 기본적으로 다음과 같이 코드를 고쳐 쓰는 것으로 POSIX에 의해 발생하는 파이프/서브셸 문제를 회피하는 것을 의미합니다.

some_command | read a b c

다음과 같이 입력합니다.

read a b c << EOF
$(some_command)
EOF

코드는 다음과 같습니다.

some_command |
while read a b c; do
    # something
done

다음과 같이 입력합니다.

while read a b c; do
    # something
done << EOF
$(some_command)
EOF

그러나 후자는 빈 입력에서는 동일하게 동작하지 않습니다.이전 표기법에서는 while loop은 빈 입력에 입력되지 않지만 POSIX 표기법에서는 입력됩니다.EOF 전 뉴라인 때문인 것 같습니다만, 생략할 수 없습니다.오래된 표기법에 가까운 동작의 POSIX 코드는 다음과 같습니다.

while read a b c; do
    case $a in ("") break; esac
    # something
done << EOF
$(some_command)
EOF

대부분의 경우 이 정도면 충분합니다.그러나 안타깝게도 some_command가 빈 행을 출력하는 경우에도 이전 표기법과 완전히 다르게 동작합니다.이전 표기법에서는 본문이 실행되는 동안, POSIX 표기법에서는 본문 앞에서 끊습니다.

이 문제를 해결하기 위한 접근방식은 다음과 같습니다.

while read a b c; do
    case $a in ("something_guaranteed_not_to_be_printed_by_some_command") break; esac
    # something
done << EOF
$(some_command)
echo "something_guaranteed_not_to_be_printed_by_some_command"
EOF

과제를 포함한 표현에 무언가를 주입하는 것은 그렇게 행동하지 않습니다.

대신 다음을 시도해 보십시오.

test=$(echo "hello world"); echo test=$test

다음 코드:

echo "hello world" | ( test=($(< /dev/stdin)); echo test=$test )

작동하지만 파이프 뒤에 또 다른 새로운 서브셸이 열립니다.

echo "hello world" | { test=($(< /dev/stdin)); echo test=$test; }

않을 것이다.


chepnars 메서드를 사용하기 위해 작업 제어를 비활성화해야 했습니다(단말기에서 다음 명령을 실행하고 있었습니다).

set +m;shopt -s lastpipe
echo "hello world" | read test; echo test=$test
echo "hello world" | test="$(</dev/stdin)"; echo test=$test

Bash 매뉴얼 설명:

라스트 파이프

설정되어 있고 작업 제어가 활성화되지 않은 경우 셸은 현재 셸 환경에서 백그라운드에서 실행되지 않은 파이프라인의 마지막 명령을 실행합니다.

주의: 비인터랙티브셸에서는 작업 제어가 기본적으로 해제되어 있기 때문에set +m대본 안에.

stdin으로부터 입력을 받을 수 있는 셸 스크립트를 작성하려고 했던 것 같습니다.그러나 인라인으로 수행하려고 시도하는 동안 해당 test= 변수를 생성하려다 길을 잃었습니다.인라인으로 하는 것은 그다지 의미가 없다고 생각합니다.그렇기 때문에 기대했던 대로 되지 않습니다.

저는 줄이려고 노력했어요.

$( ... | head -n $X | tail -n 1 )

다양한 입력으로부터 특정 라인을 얻을 수 있습니다. 그래서 타이핑할 수 있습니다.

cat program_file.c | line 34

stdin에서 읽을 수 있는 작은 셸 프로그램이 필요해요너처럼 말이야

22:14 ~ $ cat ~/bin/line 
#!/bin/sh

if [ $# -ne 1 ]; then echo enter a line number to display; exit; fi
cat | head -n $1 | tail -n 1
22:16 ~ $ 

자, 여기 있습니다.

문제는 스크립트에서 나중에 사용할 수 있도록 변수에 저장하는 명령어의 출력을 얻는 방법입니다.이전 답변을 반복할 수도 있지만 비교와 코멘트를 위해 생각할 수 있는 모든 답변을 나열하려고 합니다.그러니까 조금만 참아주세요.

직관적인 구성

echo test | read x
echo x=$x

는 Korn 쉘에서 유효합니다.ksh는 파이핑된 시리즈의 마지막 명령어가 현재 셸 ie의 일부임을 실장하고 있기 때문입니다.이전 파이프 명령은 하위 쉘입니다.반면 다른 셸에서는 파이핑된 모든 명령어를 마지막 셸을 포함한 하위 셸로 정의합니다.이것이 바로 내가 ksh를 선호하는 이유입니다.그러나 다른 셸인 bash f.ex.를 사용하여 복사해야 하므로 다른 구성을 사용해야 합니다.

1개의 값을 얻기 위해서는 이 구조가 유효합니다.

x=$(echo test)
echo x=$x

단, 나중에 사용하기 위해 수집되는 값은 1개뿐입니다.

값을 더 많이 잡으려면 이 구성이 유용하며 bash 및 ksh에서 작동합니다.

read x y <<< $(echo test again)
echo x=$x y=$y

bash에서는 동작하지만 ksh에서는 동작하지 않는 바리안트가 있습니다.

read x y < <(echo test again)
echo x=$x y=$y

<<$(...)>는 표준 명령줄의 모든 메타 처리를 제공하는 본 문서의 변형입니다.<(...)는 파일 압축 연산자의 입력 리다이렉트입니다.

현재 모든 스크립트에서 "<< $(")"를 사용하고 있습니다. 왜냐하면 "<"는 셸 바리안트 간에 가장 이식성이 높은 구성이기 때문입니다.어떤 Unix 플레이버라도 작업 시 가지고 다닐 수 있는 도구 세트가 있습니다.

물론 보편적으로 실행 가능하지만 대략적인 해결책이 있습니다.

command-1 | {command-2; echo "x=test; y=again" > file.tmp; chmod 700 file.tmp}
. ./file.tmp
rm file.tmp
echo x=$x y=$y

파라미터로 전달하거나 파이프로 연결할 수 있는 문자열을 구문 분석하는 비슷한 기능을 원했습니다.

는 다음과 같은 .#!/bin/sh그리고 로서#!/bin/bash)

#!/bin/sh

set -eu

my_func() {
    local content=""
    
    # if the first param is an empty string or is not set
    if [ -z ${1+x} ]; then
 
        # read content from a pipe if passed or from a user input if not passed
        while read line; do content="${content}$line"; done < /dev/stdin

    # first param was set (it may be an empty string)
    else
        content="$1"
    fi

    echo "Content: '$content'"; 
}


printf "0. $(my_func "")\n"
printf "1. $(my_func "one")\n"
printf "2. $(echo "two" | my_func)\n"
printf "3. $(my_func)\n"
printf "End\n"

출력:

0. Content: ''
1. Content: 'one'
2. Content: 'two'
typed text
3. Content: 'typed text'
End

마지막 케이스(3)의 경우 Enter 키를 누른 후 CTRL+D 키를 눌러 입력을 종료해야 합니다.

이거 어때:

echo "hello world" | echo test=$(cat)

언급URL : https://stackoverflow.com/questions/2746553/read-values-into-a-shell-variable-from-a-pipe

반응형