쉘 스크립트나 함수에서 파이프를 우회하는 방법이 있습니까?

쉘 스크립트나 함수에서 파이프를 우회하는 방법이 있습니까?

ps옵션이 무엇이든 또는 결과를 grep하더라도 ps열이 무엇인지 알려주는 출력의 첫 번째 줄을 얻을 수 있도록 작은 래퍼를 작성하고 싶습니다 . 예를 들어 의 출력은 ps_wrapper -aux | grep thing다음과 같습니다.

USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
name       33925  1.0  0.0   9972  5528 pts/0    Ss   19:34   0:00 /bin/thing

나는 그것이 효과가 있는지 확인하려고 노력했고 tee다음과 같은 것을 시도했습니다.

function ps_wrapper {
    tmpfile=$(mktemp)
    ps $@ > $tmpfile
    head -n 1 $tmpfile >> /dev/stdout
    cat $tmpfile
}

그러나 나는 "수동으로" 작성하더라도 /dev/stdout여전히 grep.

ps인쇄되는 열은 사용된 옵션에 따라 변경될 수 있으므로 실행 중인 실제 명령의 첫 번째 줄을 인쇄하고 싶습니다.

저는 zsh를 사용하고 있지만 더 적합한 것이 있다면 다른 것을 사용해도 괜찮습니다.

읽어 주셔서 감사합니다.

답변1

일반적으로 "파이프를 우회"하는 것은 불가능합니다. 즉, 파이프 없이 출력이 갈 수 있는 곳으로 출력을 보내는 것입니다. 그러나 파이프를 우회하고 터미널과 같이 선택한 다른 위치로 출력을 리디렉션할 수 있습니다. 특수 파일은 /dev/tty항상 현재 터미널을 나타냅니다.

function ps_wrapper {
    tmpfile=$(mktemp)
    ps "$@" > $tmpfile
    head -n 1 $tmpfile >/dev/tty
    cat $tmpfile
    rm $tmpfile
}

원래 위치를 "저장"하고 아래로 전달하면 파이프를 우회할 수도 있습니다.파일 설명자를 통해. 하지만 ps_wrapper함수에서는 그렇게 할 수 없습니다 .

function ps_wrapper {
    tmpfile=$(mktemp)
    ps "$@" > $tmpfile
    head -n 1 $tmpfile >&3
    cat $tmpfile
    rm $tmpfile
}
{ ps_wrapper … | grep …; } 3>&1

임시 파일 생성을 방지하는 방법에는 여러 가지가 있습니다. 몇 가지를 언급하겠습니다. 달리 명시하지 않는 한, 이 답변의 솔루션은 다음과 같은 경우 bash에서 작동합니다.변수 및 명령 대체 주위에 큰따옴표 추가.

함수 호출 방식을 변경하려는 경우 head파이프 오른쪽에서 및 연속적으로 두 가지를 모두 호출할 수 있습니다. 첫 번째 줄을 읽고 인쇄하고 나머지는 후속 작업을 위해 남겨 둡니다.grephead

ps … | { head -n 1; grep …; }

당신은 할 수프로세스 교체그리고 tee또는zsh에 tee유사한 기능 내장( multios)출력을 복사하려면 하나의 스트림을 head -n 1선택한 명령으로 보내고 다른 스트림을 선택한 명령으로 보냅니다. 그러나 각 스트림을 명령으로 파이프하면 둘 사이에 경합이 발생하고 head속도가 충분히 빠르지 않으면 첫 번째 줄이 맨 위에 표시되지 않을 수 있습니다. 상당히 빠르기 때문에 자주 작동할 수 있지만 , 예를 들어 디스크 캐시에 head있지만 그렇지 않은 경우에는 보장할 수 없습니다 .grephead

ps | tee >(head -n 1 >/dev/tty) | grep …
ps >(head -n 1 >/dev/tty) | grep …         # zsh only, only if multios is not disabled

awk를 사용하여 첫 번째 줄을 표시한 다음 나머지 줄을 전달할 수 있습니다.

function ps_wrapper {
  ps "$@" | awk 'NR == 1 {print >"/dev/tty"} NR != 1 {print}'
}

설명하다:

  • awk는 입력을 한 줄씩 처리합니다.
  • 건강 상태{암호} 구현하다암호만족의 선에서건강 상태.
  • NR줄 번호입니다.
  • awk의 리디렉션은 셸과 정확히 동일하게 작동하지는 않지만 충분히 유사합니다.
  • print인수 없이 입력 행을 인쇄합니다.

또 다른 접근 방식은 필터 기능을 단일 명령으로 구축하는 것입니다. 인수에 표시되지 않는 ps구분 기호 로 사용할 문자열을 선택하세요(예: ) |.

function pipe_preserving_first_line {
  local lhs
  lhs=()
  while [[ $1 != '|' ]]; do
    lhs+=($1)
    shift
  done
  shift
  "${lhs[@]}" | {
    head -n 1;
    "$@"
  }
}
pipe_preserving_first_line ps u \| grep foo

예를 들어 , 명령 이름으로 프로세스를 일치시키려면 psgrep 대신 일치 함수를 사용할 수 있습니다 .-C

ps uww -C mycommand

grep을 사용하는 것 외에도 pgrep일치 도구를 사용할 수도 있습니다.

ps -p $(pgrep -d, mycommand)

관련 정보