특정 사용 사례:
내가 사용하려는 curl
URL은 -v
자세한 디버그 정보를 일반처럼 stderr에 출력하고, 응답 본문을 일반처럼 stdout으로 출력하지만, 정규 표현식이 응답에 있는지 확인하고 grep
찾을 수 없으면 0이 아닌 값으로 종료합니다. 이 명령의 가장 간단한 형식은 다음과 같습니다.
curl -v "${url}" | grep -q "${pattern}"
그러나 grep
응답 본문은 소비됩니다.
내가 시도한 것:
나는 본 적이 "일치하는 라인뿐만 아니라 모든 라인을 출력하도록 grep을 설득하십시오.”, 이는 다음을 제안합니다.
curl -v "${url}" | grep --color -E "${pattern}|$"
하지만 이 색상만 일치 항목을 강조 표시하므로
pattern
존재하지 않는 경우 0이 아닌 종료 코드를 제공하지 않습니다.나도 본 적 있어"grep 종료 코드를 얻지만 모든 줄을 인쇄하는 방법은 무엇입니까?", 이는 다음을 나타냅니다.
curl -v "${url}" | tee /dev/stderr | grep -q "${pattern}"
종료 코드로 종료되고 응답 본문을 인쇄하지만 응답 본문을 stderr에 인쇄하므로 stderr 및 stdout 스트림을 별도로
grep
유지하고 싶습니다 .curl
다음과 같은"파이프로 직접 출력 및 표준 출력", 나는 노력했다
curl -v "${url}" | tee >(grep -q "${pattern}")
그러나 이는 모든 것을 인쇄하고 stdout 및 stderr 스트림을 올바르게 분리하지만
grep
종료 코드는 삭제됩니다.
현재 해결 방법:
지금까지 제가 생각할 수 있는 유일한 방법은 응답 본문을 임시 파일에 붙여넣는 것입니다.
curl -v "${url}" | tee /tmp/response
grep -q "${pattern}" /tmp/response
그러면 올바른 출력과 올바른 종료 코드가 표시됩니다.
하지만 임시 파일 없이 단일 파이프로 이 작업을 수행할 수 있는 방법이 있을까요?
답변1
두 번째 대답은 올바른 방향으로 가고 있습니다. 노력하다
{ curl -v "${url}" | tee /dev/fd/3 | grep -q "${pattern}";} 3>&1
간략한 설명:
파일 설명자
3>&1
1(표준 출력)을 파일 설명자 3(표준 사용이 없는 가장 낮은 설명자)에 복사합니다. 이는 전체 파이프라인(즉, 전체 명령줄)의 표준 출력을 나타냅니다. 새 파일 설명자(3)는 전체 파이프라인에 유효합니다.어떤 숫자든 사용할 수 있습니다(적어도 최대 9까지). POSIX 쉘 명령 언어사양, 2.7 리디렉션,설명하다
…모든 구현은 최소한 0부터 9까지 지원해야 합니다…
POSIX 호환 쉘은 9보다 큰 숫자를 인식하지 못할 수도 있습니다. 그리고
bash(1)
설명하다9보다 큰 파일 설명자를 사용하는 리디렉션은 주의해서 사용해야 합니다.
tee /dev/fd/3
tee
파일 설명자 3에 쓰라고 지시하므로tee
파이프의 표준 출력에 연결됩니다.- 지시문에서 사용한 것과 동일한 번호를 여기에 사용해야 합니다
n>&1
. - Linux가 아닌 운영 체제에서는 유사한 파일 이름이 작동하지 않을 수 있습니다.
/dev/fd/n
이것은 stdout과 아무 관련이 없습니다.의
tee
, 이는 에 대한 파이프라인입니다grep
.- 지시문에서 사용한 것과 동일한 번호를 여기에 사용해야 합니다
스티븐 차제라스지적:
grep -q
패턴이 발견되면 종료합니다.tee
이후에 출력이 기록되면 종료됩니다. GNU 구현은tee
최소한-p
SIGPIPE를 무시하고 여전히 출력을 얻는 대상에 계속 쓸 수 있습니다. 또한 일부 셸은 파이프라인의 마지막 구성 요소만 기다리므로 여기에서grep -q
패턴이 발견되면 스크립트의 나머지 부분이 전달됩니다.
형식적으로 첫 번째 사항을 확인했습니다. (패턴이 일치할 경우 파이프가 조기 종료될 수 있음) 1 .
저는 두 가지 문제를 모두 해결하기 위해 다음과 같은 향상된 솔루션을 제공합니다.
{ curl -v "${url}" | tee /dev/fd/3 | { grep -q "${pattern}" && cat > /dev/null;} } 3>&1
노트:
- 데이터 흐름이라면아니요패턴과 일치하면
grep
전체 스트림(즉, 입력)을 읽으므로 문제가 발생하지 않습니다. 그리고 이 경우에는grep
"실패"하므로 는&&
실행되지 않고 복합 명령은 에서cat
종료 코드를 반환합니다 .grep
즉, 실패합니다(즉, 일치하지 않음). - 데이터 흐름이라면하다패턴과 일치하면 (Stéphane이 지적했듯이)
grep
패턴이 일치하면 종료되고 전체 입력(즉, 출력curl | tee
)은 읽혀지지 않습니다. 하지만 이 경우에는grep
"성공"할 것이므로&&
,cat
~ 할 것이다실행하면 나머지 데이터가 흡수됩니다(EOF까지). 이렇게 하면tee
전체 데이터 스트림이 파이프에 기록될 수 있으며curl
모든 출력이 처리될 때까지 파이프(즉, 전체 명령줄)가 종료되지 않습니다.
기술적으로 이는 여전히 문제를 남깁니다. 데이터 흐름이 패턴과 일치하고 grep
"성공"하면 파이프라인의 종료 상태는 의 종료 상태가 됩니다 cat
. 왜 실패하는지 모르겠지만 (pipe) | cat > /dev/null
이론적으로는 가능합니다. 이를 방지하기 위해 나는 다음을 제안합니다.
{ curl -v "${url}" | tee /dev/fd/3 | if grep -q "${pattern}"; then cat > /dev/null; true; else false; fi; } 3>&1
성공하면 명시적으로 true를 반환 grep
하고 실패하면 false를 반환합니다.
______________
1개의 옵션 이 추가 -p
되었습니다 .tee
버전 8.24 (2015-07-03).
위의 변형 중 원하는 경우 관로다른 곳에서 오는 출력의 경우 curl
평소와 같이 명령줄 끝에 파이프를 추가하면 됩니다.
{ curl …; fi; } 3>&1 | lpr
하지만 원한다면리디렉션파일에 저장하려면 출력 리디렉션을 삽입해야 합니다.앞으로이것 3>&1
:
{곱슬...;수수료;}>결과물 파일3>&1
"파일로 파이핑"은 잘못된 용어라는 점을 기억하세요.
답변2
여기에 특별한 것이 없으면 grep
awk를 사용하여 패턴 일치를 수행할 수도 있습니다.
curl -v "${url}" | awk -v p="$pattern" '$0 ~ p {found=1} {print} END {exit ! found}'
-v p="$pattern"
awk 변수를p
쉘 변수의 값으로 설정하십시오.pattern
$0 ~ p {found=1}
found
행이p
변수의 정규식과 일치하면 awk 변수가 1로 설정됩니다.{print}
- 모든 행을 인쇄합니다(이 블록에는 조건이 제공되지 않으므로).END {exit ! found}
- 입력이 끝나면 음수 상태로 종료됩니다found
(따라서 패턴이 일치하면 0, 그렇지 않으면 1).
awk와 grep은 다양한 정규식을 지원하므로 패턴을 변경해야 할 수도 있습니다.