파이프가 비어 있는지 확인하고 데이터가 없으면 명령을 실행하는 방법은 무엇입니까? “fill” 산출: fill echo “string” | tail

bash 스크립트로 줄을 파이프로 묶어 파이프에 데이터가 있는지 확인하고 프로그램에 공급하기 전에 파이프에 데이터가 있는지 확인하고 싶습니다.

내가 찾은 검색 test -t 0하지만 여기서 작동하지 않습니다. 항상 false를 반환합니다. 파이프에 데이터가 있는지 확인하는 방법은 무엇입니까?

예:

echo "string" | [ -t 0 ] && echo "empty" || echo "fill"

산출: fill

echo "string" | tail -n+2 | [ -t 0 ] && echo "empty" || echo "fill"

산출: fill

앞서 언급 한 파이프 라인이 출력을 생성하는지 테스트하는 표준 / 정규 방법 과 달리 ? 입력을 프로그램으로 전달하려면 입력을 보존해야합니다. 이것은 한 프로세스에서 다른 프로세스로 출력을 파이프하는 방법을 일반화 하지만 첫 번째 출력이있는 경우에만 실행합니까? 이메일 발송에 중점을 둡니다.



답변

일반적으로 사용 가능한 쉘 유틸리티를 사용하여 파이프의 내용을 들여다 볼 수 없으며 파이프의 문자를 읽은 다음 다시 넣을 수있는 방법도 없습니다. 파이프에 데이터가 있음을 알 수있는 유일한 방법은 바이트를 읽는 것입니다. 그런 다음 해당 바이트를 대상으로 가져와야합니다.

그렇게하십시오 : 1 바이트를 읽으십시오; 파일의 끝을 감지하면 입력이 비어있을 때 수행 할 작업을 수행하십시오. 바이트를 읽는 경우 입력이 비어 있지 않은 경우 수행하려는 작업을 포크하고 해당 바이트를 파이프로 보내고 나머지 데이터를 파이프하십시오.

first_byte=$(dd bs=1 count=1 2>/dev/null | od -t o1 -A n | tr -dc 0-9)
if [ -z "$first_byte" ]; then
  # stuff to do if the input is empty
else
  {
    printf "\\$first_byte"
    cat
  } | {
    # stuff to do if the input is not empty
  }
fi

ifne에서 유틸리티 조이 헤스의 moreutils는 입력이 비어 있지 않은 경우 명령을 실행합니다. 일반적으로 기본적으로 설치되지 않지만 대부분의 유닉스 변형에서 사용 가능하거나 쉽게 빌드 할 수 있어야합니다. 입력이 비어 있으면 ifne아무것도하지 않고 상태 0을 리턴하는데, 이는 성공적으로 실행중인 명령과 구별 할 수 없습니다. 입력이 비어있는 경우 무언가를 수행하려는 경우, 성공 사례가 구별 가능한 오류 상태를 리턴하도록하여 수행 할 수있는 명령이 0을 리턴하지 않도록 배열해야합니다.

ifne sh -c 'do_stuff_with_input && exit 255'
case $? in
  0) echo empty;;
  255) echo success;;
  *) echo failure;;
esac

test -t 0이것과 아무 관련이 없습니다. 표준 입력이 터미널인지 테스트합니다. 어떤 입력을 사용할 수 있는지 여부에 대해서는 어떤 식 으로든 말하지 않습니다.


답변

간단한 해결책은 ifne명령 을 사용하는 것입니다 (입력이 비어 있지 않은 경우). 일부 배포판에서는 기본적으로 설치되지 않습니다. moreutils대부분의 배포판 에서 패키지의 일부입니다 .

ifne 표준 입력이 비어 있지 않은 경우에만 지정된 명령을 실행합니다.

표준 입력이 비어 있지 않으면 ifne주어진 명령으로 전달됩니다.


답변

오래된 질문이지만 내가 한 것처럼 누군가가 그것을 만난 경우 : 내 해결책은 시간 초과로 읽는 것입니다.

while read -t 5 line; do
    echo "$line"
done

stdin비어 있으면 5 초 후에 반환됩니다. 그렇지 않으면 모든 입력을 읽고 필요에 따라 처리 할 수 ​​있습니다.


답변

stdin (0)의 파일 디스크립터가 열려 있는지 또는 닫혀 있는지 확인하십시오.

[ ! -t 0 ] && echo "stdin has data" || echo "stdin is empty"


답변

test -s /dev/stdin명시 적 서브 쉘에서 사용할 수도 있습니다 .

# test if a pipe is empty or not
echo "string" |
    (test -s /dev/stdin && echo 'pipe has data' && cat || echo 'pipe is empty')

echo "string" | tail -n+2 |
    (test -s /dev/stdin && echo 'pipe has data' && cat || echo 'pipe is empty')

: | (test -s /dev/stdin && echo 'pipe has data' && cat || echo 'pipe is empty')


답변

bash에서 :

read -t 0 

입력에 데이터가 있는지 감지합니다 (아무것도 읽지 않음). 그런 다음 입력을 읽을 수 있습니다 (읽기 실행시 입력을 사용할 수있는 경우).

if     read -t 0
then   read -r input
       echo "got input: $input"
else   echo "No data to read"
fi

참고 : 타이밍에 따라 다릅니다. 입력 한 시간에 입력에 이미 데이터가 있는지 여부를 감지합니다 read -t.

예를 들어

{ sleep 0.1; echo "abc"; } | read -t 0; echo "$?"

출력은 1(읽기 실패, 즉 빈 입력)입니다. echo는 일부 데이터를 기록하지만 첫 바이트를 시작하고 쓰는 속도가 빠르지 read -t 0않으므로 프로그램이 아직 아무것도 작성하지 않았기 때문에 입력이 비어 있다고보고합니다.


답변

유닉스에서 읽을 수있는 데이터가 있는지 확인하는 쉬운 방법 중 하나는 FIONREADioctl을 사용하는 것입니다.

나는 그것을하는 표준 유틸리티를 생각할 수 없으므로 여기에 그것을하는 사소한 프로그램이 있습니다 ( ifnemoreutils IMHO 😉 보다 낫습니다 ).

fionread [ prog args ... ]

stdin에 사용 가능한 데이터가 없으면 상태 1로 종료됩니다 prog. 데이터가 있으면 실행 됩니다. prog지정 하지 않으면 상태 0으로 종료됩니다.

즉시 사용 가능한 poll데이터에만 관심이있는 경우 통화 를 제거 할 수 있습니다. 파이프뿐만 아니라 대부분의 fd에서 작동합니다.

fionread.c

#include <unistd.h>
#include <poll.h>
#include <sys/ioctl.h>
#ifdef __sun
#include <sys/filio.h>
#endif
#include <err.h>

int main(int ac, char **av){
        int r; struct pollfd pd = { 0, POLLIN };
        if(poll(&pd, 1, -1) < 0) err(1, "poll");
        if(ioctl(0, FIONREAD, &r)) err(1, "ioctl(FIONREAD)");
        if(!r) return 1;
        if(++av, --ac < 1) return 0;
        execvp(*av, av);
        err(1, "execvp %s", *av);
}