install.sh
기본적으로 다음과 같은 스크립트가 있습니다 .
#!/bin/bash
if [[ ! -f "/usr/bin/jq" ]]; then
apt-get update && apt-get install -y jq
fi
echo $(date) >> install.log
서버에 놓고 다음과 같이 실행하면:
curl -s0 https://myserver.com/install.sh | bash
미친 apt-get
출력 후에 echo
는 마지막 줄을 실행하는 대신 해당 줄을 echo $(date) >> test.log
출력으로 인쇄합니다. 반면에 install.sh
디스크에 저장 하고 실행하면 ./install.sh
예상대로 작동합니다. 에코 라인을 실행하고 install.log
추가합니다.
문제를 추가로 재현하기 위해 다음과 같이 로컬에서 실행했습니다.
cat install.sh | bash
또한 동일한 문제가 있습니다.
apt-get remove jq
각 테스트 전에 수동으로 실행합니다 . 설치 하면 jq
둘 다 예상대로 작동합니다. 그렇다면 다운로드에서 실행하는 것과 로컬 파일에서 실행하는 것이 왜 다른가요?
이 문제를 설명하기 위해 짧은 비디오를 녹화했습니다.https://www.youtube.com/watch?v=lYvGXI7AibA
답변1
일반적 bash
으로 파일( bash foo
예 bash <foo
: . 그러나 이제는 apt-get
사용자에게 묻고자 하는 명령( )을 시작 하고 STDIN을 사용하여 그렇게 합니다.
그래서 이상한 일이 일어납니다. bash는 STDIN에서 명령을 읽고 하나씩 실행합니다. 이제 명령 중 하나가 STDIN에서 읽고 파일의 다음 줄을 읽습니다. 그 후 bash는 STDIN에서 다음 줄을 읽으므로 다른 명령이 이미 읽은 명령 하나를 건너뜁니다.
이 작은 스크립트는 무슨 일이 일어나고 있는지 보여줍니다.
echo "hello"
read -p "how do you do? "
echo "I understand"
echo "you are '$REPLY'."
echo "bye"
파일에 저장하고 bash -x foo
먼저 as를 실행한 다음 as를 실행합니다 bash -x <foo
.
귀하의 경우에도 같은 일이 발생합니다.
한 가지 해결책은 프로세스 대체를 사용하는 것입니다.
bash -x <(cat foo)
또는 귀하의 경우 간단히:
bash <(curl -s0 https://myserver.com/install.sh)
몇 가지 참고사항:
쉘 스크립트가 이상한 일을 할 때마다 bash -x
무슨 일이 일어나고 있는지 확인하는 데 사용하십시오.
글쓰기 cat foo| ...
가 불린다고양이에게 쓸모없는 용도. 리디렉션을 사용하면 됩니다.