우아한 방법으로 영원히 아무것도하지 않는 방법?


82

유용한 정보를 생성 stdout하지만에서 읽는 프로그램이 있습니다 stdin. 표준 입력에 아무것도 제공하지 않고 표준 출력을 파일로 리디렉션하고 싶습니다. 지금까지는 너무 좋습니다.

program > output

tty에서 아무것도하지 마십시오.

그러나 문제는 백그라운드에서 이것을하고 싶습니다. 만약 내가한다면:

program > output &

프로그램이 일시 중단됩니다 ( "일시 중단 (tty input)").

만약 내가한다면:

program < /dev/null > output &

EOF에 도달하면 프로그램이 즉시 종료됩니다.

내가 필요한 것은 program무한한 시간 동안 아무것도하지 않고 읽지 않는 것으로 파이프하는 것 같다 stdin. 다음과 같은 접근 방식이 작동합니다.

while true; do sleep 100; done | program > output &
mkfifo fifo && cat fifo | program > output &
tail -f /dev/null | program > output &

그러나 이것은 모두 매우 추악합니다. 가 있다 (의역 "무기한, 아무것도하지"로, 표준 유닉스 유틸리티를 사용하여, 우아한 방법이 man true). 어떻게하면 되나요? (여기서 우아함에 대한 나의 주요 기준 : 임시 파일, 바쁜 대기 또는 주기적 깨우기, 이국적인 유틸리티 없음, 가능한 한 짧음)


시도하십시오 su -c 'program | output &' user. "서비스 / 데몬"을 처리하기위한 적절한 방법으로 백그라운드 작업을 만드는 것과 비슷한 질문을하려고합니다. 또한 리디렉션 STDERR하지 않고 리디렉션 할 수없는 것으로 나타났습니다 STDOUT. programA가 전송 솔루션 STDOUTSTDINprogramB의 후 리디렉션 STDERR로그 파일 :programA 2> /var/log/programA.log | programB 2> /var/log/programB.log 1> /dev/null
mbrownnyc

아마도 ... su -c 'while true; do true; done | cat > ~/output &' user?
mbrownnyc

어떤 종류의 프로그램입니까?
João Portela

João Portela : 이것은 내가 작성한 프로그램 gitorious.org/irctk
a3nm

작성한 프로그램에 스위치를 추가하는 것이 어떻습니까? 또한 stdin을 닫으면 1<&-프로그램이 종료 된다고 가정합니다 .
w00t

답변:


16

이를 지원하는 쉘 (ksh, zsh, bash4)에서는 공동 프로세스program 로 시작할 수 있습니다 .

  • ksh: program > output |&
  • zsh, bash:coproc program > output

program입력이에서 리디렉션되어 백그라운드에서 시작됩니다 pipe. 파이프의 다른 쪽 끝은 쉘에 열려 있습니다.

그 접근법의 세 가지 장점

  • 추가 프로세스가 없습니다
  • program죽으면 스크립트를 종료 할 수 있습니다 ( wait대기하기 위해 사용 )
  • program종료됩니다 ( eof쉘이 종료되면 stdin을 얻 습니다).

그것은 효과가 있고 좋은 생각처럼 보입니다! (공평하게, 나는 쉘 기능이 아니라 내 명령에 파이프 할 것을 요구했지만 이것이 XY 문제 일뿐입니다.) @PT 대신이 답변을 수락하는 것을 고려하고 있습니다.
a3nm

1
@ a3nm tail -f /dev/null은 매초마다 읽기를 수행하기 때문에 이상적이지 않습니다 /dev/null(Linux에서 현재 GNU tail의 현재 버전은 실제로 버그가 있음을 나타냅니다). sleep inf또는 그 이상의 휴대용 상당 sleep 2147483647(점에 유의 IMO 아무것도하지 않고 거기에 앉아 명령에 대한 더 나은 방법입니다 sleep같은 몇 가지 껍질에 내장 ksh93또는 mksh).
Stéphane Chazelas

78

난 당신 이보다 더 우아한 얻을 것이라고 생각하지 않습니다

tail -f /dev/null

이미 제안했습니다 (이것이 내부적으로 inotify를 사용한다고 가정하면, 폴링이나 웨이크 업이 없어야하므로 이상해 보이는 것 이외는 충분해야합니다).

무기한으로 실행되고 stdout을 열린 상태로 유지하지만 실제로 stdout에 아무것도 쓰지 않으며 stdin이 닫힐 때 종료되지 않는 유틸리티가 필요합니다. 같은 뭔가 yes실제로는 표준 출력에 기록합니다. catstdin이 닫히면 (또는 리디렉션하는 것이 끝나면) 종료됩니다. 나는 효과가 있다고 생각 sleep 1000000000d하지만 tail분명히 더 낫습니다. 내 데비안 상자에는 tailf명령이 약간 단축되었습니다.

다른 압정을 사용하여 프로그램을 실행하는 것은 screen어떻습니까?


나는 tail -f /dev/null명령 사용법이 의도 된 목적과 매우 밀접하게 일치하기 때문에 접근법을 가장 좋아 하고 충분히 우아하게 생각합니다.
jw013

2
에서 strace tail -f /dev/null그것은 그 보인다 tail사용 inotify깨우는이 바보 같은 경우에 발생할 있고 sudo touch /dev/null. 더 나은 솔루션이없는 것 같습니다 ... 더 나은 솔루션을 구현하는 데 사용할 syscall이 어떤 것인지 궁금합니다.
a3nm

5
@ a3nm syscall은 pause이지만 쉘 인터페이스에 직접 노출되지는 않습니다.
Gilles

PT :에 대해 알고 screen있지만 테스트 목적으로 쉘 스크립트에서 프로그램을 여러 번 실행하므로 screen약간의 과잉 사용 이 필요합니다.
a3nm

3
@sillyMunky Silly Monkey, WaelJ의 답변이 잘못되었습니다 (stdin에 무한의 0을 보냅니다).
PT

48

sleep infinity 내가 아는 가장 명확한 해결책입니다.

부동 소수점 숫자 *를 허용 하기 infinity때문에 사용할 수 있습니다. * , 십진수 , 16 진수 , 무한대 또는 NaN 일 수 있습니다.sleepman strtod

* 이것은 POSIX 표준의 일부가 아니므로로 이식 할 수 없습니다 tail -f /dev/null. 그러나 GNU coreutils (Linux) 및 BSD (Mac에서 사용)에서 지원됩니다 (맥의 최신 버전에서는 지원되지 않습니다. 주석 참조).


하하, 정말 좋은 접근법입니다. :)
a3nm

@ a3nm : 감사합니다 :) BSD 및 Macsleep infinity 에서도 작동합니다 .
Zaz

무한 수면 과정에는 어떤 종류의 자원이 필요합니까? 그냥 RAM?
CMCDragonkai

1
이 답변sleep infinity 은 최대 24 일 동안 대기 한다고 주장합니다 . 누가 맞아?
nh2

1
@Zaz 지금 문제를 자세히 조사했습니다. 처음에 옳았다는 것이 밝혀졌습니다! 이 sleep유틸리티는 24 일로 제한되지 않습니다 . 24 일 동안 잠을 잔다는 것은 첫 번째 시스템 콜일 뿐이며 이후에는 더 많은 시스템 콜을 수행하게됩니다. 내 의견보기 here : stackoverflow.com/questions/2935183/…
nh2

19
sleep 2147483647 | program > output &

예, 2^31-1유한 한 숫자이며 영원히 실행되지는 않지만 수면이 마침내 시간 초과되면 1000 달러를 줄 것입니다. (힌트 : 그때 우리 중 한 명이 죽을 것입니다.)

  • 임시 파일이 없습니다. 검사.
  • 바쁜 대기 또는 주기적 깨우기; 검사
  • 이국적인 유틸리티가 없습니다. 검사.
  • 가능한 한 짧게 좋아요. 짧아 질 수 있습니다.

5
bash : 수면 $ ((64 # 1 _____)) | 프로그램> 출력 &
Diego Torres Milano

68 년 동안 자고, 98 세기 동안sleep 2147483647d
자다

9

다음을 사용하여 바이너리를 만들 수 있습니다.

$ echo 'int main(){ pause(); }' > pause.c; make pause

5

다음은 표준 유닉스 유틸리티를 사용하여 "무한을하지 않는다"는 또 다른 제안 입니다.

sh -c 'kill -STOP $$' | program > output

그러면 즉시 전송되는 쉘이 실행되어 SIGSTOP프로세스가 일시 중단됩니다. 이것은 프로그램에 "입력"으로 사용됩니다. 의 보완은 SIGSTOP입니다 SIGCONT. 즉, 쉘에 PID 12345가 있다는 것을 알고 kill -CONT 12345있다면 계속할 수 있습니다 .


2

Linux에서는 다음을 수행 할 수 있습니다.

read x < /dev/fd/1 | program > output

Linux에서 / dev / fd / x를 열면 여기서 x는 파이프의 쓰기 끝에 대한 파일 디스크립터이며 파이프의 읽기 끝을 가져옵니다. 여기에서 프로그램의 표준 입력과 동일합니다. 따라서 기본적으로 read파이프에 쓸 수있는 유일한 것은 자체이며 read아무것도 출력하지 않기 때문에 반환 하지 않습니다.

또한 FreeBSD 또는 Solaris에서도 작동하지만 다른 이유가 있습니다. 거기에서 / dev / fd / 1을 열면 예상대로 fd 1에서 열었던 것과 동일한 리소스를 얻을 수 있으며 Linux를 제외한 대부분의 시스템에서 파이프의 쓰기 끝이 발생합니다. 그러나 FreeBSD 및 Solaris에서 파이프는 양방향입니다. 따라서 programstdin에 쓰지 않는 한 (응용 프로그램이 없음) read파이프의 해당 방향에서 읽을 내용이 없습니다.

파이프가 양방향이 아닌 시스템에서는 read쓰기 전용 파일 디스크립터에서 읽을 때 오류가 발생하여 실패 할 수 있습니다. 또한 모든 시스템에이 시스템이있는 것은 아닙니다 /dev/fd/x.


아주 좋아요! 사실 내 테스트 x에는 bash 가 필요하지 않습니다 . zsh를 사용하면 방금 할 수 있으며 read작동합니다 (왜 그런지 이해하지 못합니다!). 이 트릭은 Linux에만 해당됩니까, 아니면 모든 * nix 시스템에서 작동합니까?
a3nm

@ a3nm, read혼자 할 경우 stdin에서 읽습니다. 따라서 터미널 인 경우 enter를 누를 때까지 입력 한 내용을 읽습니다.
Stéphane Chazelas

확실히, 나는 읽는 것이 무엇인지 이해합니다. 내가 이해하지 못하는 것은 백그라운드 프로세스에서 읽은 터미널에서 읽는 것이 bash로 차단되지만 zsh로는 차단되지 않는 이유입니다.
a3nm

@ a3nm, 무슨 말인지 모르겠습니다. 당신이 할 read있고 그것이 작동 한다는 것은 무엇을 의미 합니까?
Stéphane Chazelas

zsh를 사용하면 할 수 있으며 read | program > output제안한 것과 같은 방식으로 작동합니다. (그리고 나는 왜 그런지 모르겠다)
a3nm

0

Stéphane Chazelas의 read 솔루션 은에서 읽기 fd가 열리면 Mac OS X에서도 작동합니다 /dev/fd/1.

# using bash on Mac OS X
# -bash: /dev/fd/1: Permission denied
read x </dev/fd/1 | cat >/dev/null
echo ${PIPESTATUS[*]}   #  1 0

exec 3<&- 3</dev/fd/1
read x 0<&3 | cat >/dev/null
echo ${PIPESTATUS[*]}   #  0 0

tail -f /dev/null스크립트 를 죽일 수 있으려면 (예를 들어 SIGINT를 사용하여) tail명령 을 백그라운드로 지정해야합니다 wait.

#!/bin/bash
# ctrl-c will kill tail and exit script
trap 'trap - INT; kill "$!"; exit' INT
exec tail -f /dev/null & wait $!

-2

/dev/zero표준 입력으로 리디렉션 !

program < /dev/zero > output &

9
이것은 그의 프로그램에 무한의 0 바이트를 줄 것입니다 ... 슬프게도 바쁘게 만들 것입니다.
Jander

1
이것은 사실이 아니며, / dev / zero는 파이프 체인을 열어두고 닫히지 않습니다. 그러나 포스터에 따르면 그는 stdin을 사용하지 않으므로 프로그램에 0이 전송되지 않습니다. 이것은 바쁜 루프가 아니며 순수한 대기입니다.
sillyMunky

2
죄송합니다. OP는 stdin을 사용하므로 입력 내용이 지워지고 / dev / zero에서 그립니다. 다음에 두 번 읽어야합니다! OP가 stdin을 사용하지 않았다면 이것이 내가 본 가장 우아한 솔루션 일 것이므로 바쁘지 않을 것입니다.
sillyMunky
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.