파이프를 통해 T-피스로 내보내면 조건이 깨집니다.

파이프를 통해 T-피스로 내보내면 조건이 깨집니다.

서버에 사용자 지정 방화벽 규칙이 있는지 테스트하려고 합니다. awk를 사용하여 iptables 출력을 처리하고 적절한 종료 코드를 반환함으로써 이를 수행합니다. 이는 예상대로 작동하고 올바른 결과를 인쇄합니다. 그러나 티에 파이프로 연결하면 조건이 더 이상 작동하지 않으며 매번 결과가 인쇄됩니다.

# The broken code
ssh server1 'sudo iptables -L | awk "(!/ACCEPT/ && !/^target/ && !/^$/) {rules=1 ;} (rules==1) {exit 1}" && printf "%s\n" "string1" "string2" | sudo tee -a /path/to/file'
# The same code without `| sudo tee -a /path/to/file` works as intended
ssh server1 'sudo iptables -L | awk "(!/ACCEPT/ && !/^target/ && !/^$/) {rules=1 ;} (rules==1) {exit 1}" && printf "%s\n" "string1" "string2"'

내가 무엇을 놓치고 있나요? 저는 RHEL8에서 GNU coretils 8.30 및 GNU bash 버전 4.4.20(1)을 사용하고 있습니다. 방금 awk 문이 단축될 수 있다는 것을 알았지만 그게 요점이 아닙니다. :D

답변1

귀하의 불만사항은 주로 파이프에서 반환된 상태에 관한 것입니다 iptables ... | awk ... && printf ... | tee ... . 사육제문서 그 가치가 무엇인지 설명해보세요.

파이프라인 실패 옵션이 활성화되지 않은 경우 파이프라인의 반환 상태는 마지막 명령의 종료 상태입니다. Pipefail이 활성화된 경우 파이프라인의 반환 상태는 0이 아닌 상태로 종료된 마지막(가장 오른쪽) 명령의 값이거나 모든 명령이 성공적으로 종료된 경우 0입니다.

실행을 고려해보세요

set -o pipefail

파이프라인 결과 전.

또는 더 쉽다면 ... | (cmd ... || true) | ...관용구를 사용하여 각 단계가 반환되도록 할 수 있습니다. 0예외가 감지되면 이후 파이프라인 단계에서 grep이를 처리할 수 있도록 고유한 메시지를 내보냅니다.

bash가 awk의 단순 처리와 printf의 단순 처리를 조건부로 조정하도록 하는 설계 결정은 당시에는 합리적이었을지 모르지만 이제는 이것이 생산성을 저하시킨다는 것을 알게 됩니다. 이 논리를 간단한 awk 스크립트에 통합하는 것을 고려해보세요.


더 짧은 파이프를 사용하는 것이 더 편리할 수도 있습니다.

ssh server1 ... | awk ...  > server1.txt
# awk exit status is now available in $? so you can conditionally run printf

cat server1.txt  >> /path/to/file

원래 질문에서 /path/to/file은 서버 경로 이름이었고 우리는 약간 복잡한 한 줄 원격 파이프라인을 실행하고 있었습니다. iptables -L SSH 연결을 통해 원시 출력을 반환하고 로컬 파이프라인을 실행하는 것이 더 편리 할 수 있습니다 . 로컬 결과 파일을 생성한 후에는 언제든지 다음과 같이 저장할 수 있습니다.

cat results.txt | ssh server1 'cat >> /path/to/file'

관련 정보