파이프에서 사용자 입력을 읽는 방법은 무엇입니까?

파이프에서 사용자 입력을 읽는 방법은 무엇입니까?

다음과 같은 파일이 있다고 가정해 보겠습니다 confirmation.sh.

#!/bin/bash
echo -n "Are you sure [Y/n]? "
read line
case "$line" in
    n|N) echo "smth"
        ;;
    y|Y) echo "smth"
        ;;
esac

다음과 같이 스크립트를 실행하고 싶습니다.

cat confirmation.sh | sh

알겠습니다 Are you sure [Y/n]?. 스크립트가 중단되었습니다. 문제는 무엇입니까?

답변1

다른 사람들이 말했듯이 이는 파이프에서 읽도록 리디렉션되었기 때문에 평소처럼 터미널에 연결되지 않았기 stdin때문 입니다. sh이 문제를 해결하기 위해 할 수 있는 한 가지는 /dev/tty강제 스크립트를 사용하여 터미널에서 읽는 것입니다. 예를 들어:

#!/bin/sh

read -p "Are you sure [Y/n]?" line </dev/tty
case "$line" in
  y|Y) echo "confirmed"
    ;;
  *) echo "not confirmed"
    ;;
esac

일반적으로 사람들이 입력 스크립트를 작성하는 것을 특별히 방지하려는 경우에만 이 작업을 수행합니다. 예를 들면 다음과 같습니다.

echo Y | sh confirmation.sh

사용자가 메시지가 표시될 때 자동으로 입력하기를 원하더라도 Y여전히 터미널에서 읽습니다. 이는 이 작업을 수행하기 위해 암호가 필요한 프로그램에서 일반적입니다.

답변2

sh 3<<CONFIRM /dev/fd/3
    $(cat ./confirmation.sh)
CONFIRM

sh 3<./confirmation.sh /dev/fd/3

노트:위의 두 가지 예를 수정해 준 @Graeme에게 감사드립니다...

꾸준히 하면 훨씬 쉬울 거예요stdin분명한.

2<./confirmation.sh . /dev/stderr

또는 터미널 0 1 2가 모두 동일한 파일이므로 다음을 추가하면 됩니다.

read line <&2

그리고 당신 것

cat ./confirmation.sh | sh

좋은 결과.

답변3

이는 내 스크립트에 파이프된 단일 매개변수에 대해 작동합니다.

if [ -p /dev/stdin ]; then set -- "$( cat )"; fi

$1그런 다음 다른 스크립트 작업과 호환되는 위치 매개변수( )의 파이프 데이터에 액세스할 수 있습니다 .


에서 info test:

[ -p /dev/stdin ]: -p FILEFILE이 존재하고 명명된 파이프이면 참입니다.

답변4

짧은 대답은 할 수 없다는 것입니다. 파이프는 stdout을 stdin으로 리디렉션하므로 파이프 문에서 첫 번째 명령의 출력을 두 번째 명령의 입력으로 리디렉션했기 때문에 대화형 스크립트를 실행할 수 없습니다.

다음과 같이 하고 싶을 수도 있습니다:

cat confirmation.sh > ask.sh && sh ask.sh

관련 정보