이전 명령의 출력을 인수로 다음에 전달


118

데이터를 stdout ( command1 -p=aaa -v=bbb -i=4)으로 출력하는 명령이 있습니다. 출력 라인은 다음 값을 가질 수 있습니다.

rate (10%) - name: value - 10Kbps

그 '속도'를 저장하기 위해 출력을 grep하고 싶습니다 (파이프가 여기서 유용 할 것입니다). 마지막으로 두 번째 명령의 매개 변수 값이 되길 원합니다 (말하자 command2 -t=${rate}).

내 편이 까다로워 보인다. 파이프, grep, sed 등을 사용하는 방법을 더 잘 알고 싶습니다.

나는 그와 같은 많은 조합을 시도했지만 이것에 대해 혼란스러워합니다.

$ command1 -p=aaa -v=bbb -i=4 | grep "rate" 2>&1 command2 -t="rate was "${rate}

답변:


143

매우 다른 두 가지 유형의 입력을 혼동하고 있습니다.

  1. 표준 입력 ( stdin)
  2. 명령 줄 인수

이것들은 다르며 다른 목적에 유용합니다. 일부 명령은 두 가지 방식으로 입력을받을 수 있지만 일반적으로 다르게 사용합니다. 예를 들어 다음 wc명령을 사용하십시오.

  1. 다음을 통해 입력 전달 stdin:

    ls | wc -l
    

    이것은 출력의 라인을 계산합니다 ls

  2. 명령 행 인수로 입력 전달 :

    wc -l $(ls)
    

    이것은 인쇄 된 파일 목록의 계산합니다 .ls

완전히 다른 것들.

질문에 대답하기 위해 첫 번째 명령의 출력에서 ​​속도를 캡처 한 다음 두 번째 명령의 명령 줄 인수로 속도를 사용하는 것처럼 들립니다. 이를 수행하는 한 가지 방법이 있습니다.

rate=$(command1 | sed -ne 's/^rate..\([0-9]*\)%.*/\1/p')
command2 -t "rate was $rate"

의 설명 sed:

  • s/pattern/replacement/명령은 몇 가지 패턴을 대체하는 것입니다
  • 패턴은 다음을 의미합니다. 행은 "rate"( ^rate) 로 시작하고 그 뒤에 두 문자 ( ..)가오고 0 개 이상의 숫자가오고 뒤에 %, 그 뒤에 텍스트 ( .*) 가 있어야합니다.
  • \1대체에서는에서 캡처 된 첫 번째 표현식의 컨텐츠를 의미 \(...\)하므로이 경우 %부호 앞의 숫자
  • 명령 의 -n플래그는 sed기본적으로 줄을 인쇄하지 않음을 의미합니다. p의 마지막 s///명령은 여분이 있다면 광고를 출력하는 것을 의미한다. 즉, 명령은 일치하는 경우에만 무언가를 인쇄합니다.

13

나는 이것을 사용하는 경향이있다 :

command1 | xargs -I{} command2 {}

command1대체 (괄호)를 사용하여 xargs의 출력을로 전달하십시오 command2. command1이 널 종료 문자열 에 대해 find사용 -print0하고 추가 해야하는 경우 발견 된 각 항목 을 호출 합니다.-0xargsxargscommand2

귀하의 경우 (및 @Janos에서 sed 라인을 사용) :

command1 -p=aaa -v=bbb -i=4 | sed -ne 's/^rate..\([0-9]*\)%.*/\1/p' | xargs -I{} command2 -t="rate was {}"

이것은 일을 멋지게 유지하고 파이프 처리하기 때문에 내가 이것을 좋아합니다.
Mateen Ulhaq

4

command1이 echo 문을 사용하여 출력을 시뮬레이트하려면 다음을 수행하십시오.

$ echo -e "Foo\nrate (10%) - name: value - 10Kbps\nBar"
$ alias command1='echo -e "Blah\nrate (10%) - name: value - 10Kbps\nBlag"'

빠른 테스트 :

$ command1
Blah
rate (10%) - name: value - 10Kbps
Blag

그게 다 좋으 니 파싱하자.

$ command1 | grep 'rate'
rate (10%) - name: value - 10Kbps

그래서 우리는 우리가 원하는 라인을 얻 command1습니다 command2.

$ alias command2='echo'
$ command2 -t="rate was "$(command1 | grep 'rate')
-t=rate was rate (10%) - name: value - 10Kbps

"rate was "$(command1 | grep 'rate')자동으로 연결될 것으로 기대 합니다. 공백으로 인해 작동하지 않으면 대신 다음과 같이 입력을 전달할 수 있어야합니다.

$ alias command2='echo'
$ command2 -t=$(echo '"rate was ' $(command1 | grep 'rate') '"')
-t="rate was rate (10%) - name: value - 10Kbps "


2

첫 번째 작업은 해당 라인에서 요율을 추출하는 것입니다. GNU grep (포함되지 않은 Linux 또는 Cygwin)을 사용하면이 -o옵션을 사용할 수 있습니다 . 원하는 부분은 숫자 만 포함하고 그 뒤에 %부호 가있는 부분 입니다. %자체 를 추출하지 않으려면 너비0 인 lookahead assertion 과 같은 추가 트릭이 필요합니다 %.

command1 -p=aaa -v=bbb -i=4 | grep -o -P '[0-9]+(?=%)'

또 다른 가능성은 sed를 사용하는 것입니다. sed에서 행의 일부를 추출하려면 s전체 행과 일치하는 정규식 (로 시작 ^하고로 끝나는)과 함께 명령을 사용하여 $그룹으로 유지할 부분 ( \(…\))을 사용하십시오. 전체 줄을 유지할 그룹의 내용으로 바꿉니다. 일반적으로, -n기본 인쇄를 끄고 p추출 할 항목이있는 행을 인쇄 하도록 수정자를 배치 하는 옵션을 전달하십시오 (여기서는 단일 행이 있으므로 중요하지 않음). 참조 일치하는 패턴 후 라인의 부분 만 반환 하고 주변의 문자를 인쇄하지 않고 '나오지도'와 일치하는 정규식 추출 더 나오지 트릭을.

command1 -p=aaa -v=bbb -i=4 | sed 's/^.*rate(\([0-9]*\)%).*$/\1/'

sed보다 더 융통성이 있습니다. Awk는 작은 명령형 언어로 각 줄에 대한 명령을 실행합니다. 요율을 추출하는 방법은 여러 가지가 있습니다. 두 번째 필드 (기본적으로 공백은 공백으로 구분됨)를 선택하고 숫자가 아닌 모든 문자를 제거합니다.

command1 -p=aaa -v=bbb -i=4 | awk '{gsub(/[^0-9]+/, "", $2); print $2}'

이제 속도를 추출 했으므로 다음 단계는에 인수로 전달하는 것 command2입니다. 이를위한 도구는 명령 susbtitution 입니다. 명령을 안에 넣는 경우 $(…)(달러 괄호), 해당 출력이 명령 행으로 대체됩니다. 명령의 출력은 각 공백 블록에서 개별 단어로 분리되며 각 단어는 와일드 카드 패턴으로 처리됩니다. 이런 일이 일어나지 않기를 원한다면, 명령어 치환에 큰 따옴표를 넣으십시오 : "$(…)". 큰 따옴표를 사용하면 명령 출력이 단일 매개 변수로 직접 사용됩니다 (출력 끝의 줄 바꿈이 제거되는 유일한 변환입니다).

command2 -t "$(command1 -p=aaa -v=bbb -i=4 |
               sed 's/^.*rate(\([0-9]*\)%).*$/\1/')"

0

사용할 수 있으며 grepPCRE-Perl 호환 정규 표현식입니다. 이를 통해 grepping 할 때 결과에 ​​문자열 "rate"를 포함시키지 않고 rate 값과 일치하도록 lookbehind를 활용할 수 있습니다.

$ echo "rate (10%) - name: value - 10Kbps" | grep -oP '(?<=^rate \()\d+'
10

세부

위와 같이 grep작동합니다 :

  • -o찾고있는 것만 반환합니다 \d+.이 값은 괄호 안의 숫자입니다.
  • -P grep의 PCRE 기능을 활성화합니다
  • (?<=^rate \() "rate ("로 시작하는 문자열 만 반환합니다.

command2

"rate"의 가치를 얻으려면 다음 command1과 같이 실행할 수 있습니다 .

$ rate=$(command 1 | grep -oP '(?<=^rate \()\d+'

그런 다음 두 번째 명령에는 단순히 해당 변수를 사용합니다.

$ command2 -t=${rate}

당신은 공상을 얻고 한 줄로 만들 수 있습니다.

$ command2 -t=$(command1 | grep -oP '(?<=^rate \()\d+')

이것은 $(..)실행 블록 내에서 command1을 실행하고 결과를 가져 와서 command2의 -t=..스위치 에 포함시킵니다 .


0

나는 일반적으로`command`를 사용하여 출력을 다른 명령의 인수로 배치합니다. 예를 들어, freebsd에서 프로세스 foo가 소비 한 자원을 찾으려면 다음과 같습니다.

procstat -r `pgrep -x foo`

여기서 pgrep은 프로세스의 PID를 인수로 예상하는 procstat 명령에 전달되는 프로세스 foo의 PID를 추출하는 데 사용됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.