하위 프로세스(아래의 "sleep"을 제외한 항목)의 출력을 전경 명령 루프의 출력과 일치시키는 방법이 있습니까? 예를 들어:
while true
do
echo "updating screen..."
sleep 3 & # Replace with command which takes some time and updates the screen
read -s -n 1 -p "Input: " input
case "$input" in
q)
exit
;;
f)
echo 'foo'
;;
esac
done
답변1
쉘은 무엇보다도 다중 처리에 대해 가정합니다. 하나의 프로그램이 한 번에 터미널을 제어해야 합니다. 그렇지 않으면 입력(및 출력)이 깨질 것입니다. 터미널에서 입력을 받기를 원하는 "잠자기" 프로그램을 넣으면 어떻게 될까요? 키보드 입력은 어디로 전송되나요? 자식 프로세스('sleep') 또는 명령문으로 read
?
이를 통해 하위 프로세스("sleep")가 입력을 받지 못한다고 가정해야 합니다. 또한 명령 루프("q" 또는 "f" 처리)까지 기다려야 합니다.그리고하위 프로세스가 완료되었습니다. 쉘의 가정을 해결하기 위해 Python과 같은 쉘 스크립트 이외의 다른 것을 작성하는 것이 좋습니다. 그러나 앞서 설명한 것처럼 Bourne(또는 ksh, bash 또는 zsh) 쉘에서도 수행할 수 있습니다.
#!/usr/bin/python
import os, select, subprocess, sys
devnull = open('/dev/null', 'a')
# this is the same as "sleep 3 </dev/null > pipefile &" but will handle
# processing output at the same time
p = subprocess.Popen(
['/bin/sh', '-c',
'i=0; while [ $i -lt 30 ]; do echo $i; sleep 2; i=`expr $i + 1`; done' ],
stdin=devnull, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
)
command_done = False
try:
# endless loop until both input and output are done
while True:
inputs = []
# only send input to our command loop
if not command_done:
sys.stdout.write('Input: ')
sys.stdout.flush()
inputs.append(sys.stdin)
if p.returncode is None: # still not finished
p.poll()
inputs.append(p.stdout)
outputs = []
if not inputs and not outputs: # both are done
break # exit while loop
#print inputs, outputs
r, w, x = select.select(inputs, outputs, [])
#print 'r=', r, 'w=', w, 'x=', x
# input from the user is ready
for file in r:
if file is sys.stdin:
input = file.read(1)
if input == 'q':
command_done = True
if p.returncode is None:
os.kill(p.pid, 15)
elif input == 'f':
sys.stdout.write('foo\n')
# the subprocess wants to write to the terminal too
else:
input = file.readline()
sys.stdout.write(input)
finally:
if p.poll():
try:
print
os.kill(p.pid, 15)
except OSError:
pass
쉘 스크립트에서 이 작업을 수행할 수 있지만 입력/출력이 제대로 통합되지 않습니다.
#!/bin/bash
mkfifo /tmp/mergedout.p
( i=0; while [ $i -lt 30 ]; do echo $i; sleep `expr 30 - $i`; i=`expr $i + 1`; done ) </dev/null >/tmp/mergedout.p 2>&1 &
pid=$!
exec 3</tmp/mergedout.p
done=false
trap 'rm /tmp/mergedout.p' 0
while [ -n "$pid" -a $done = false ]; do
if [ $done = false ]; then
echo -n "Input: "
read -t 0.1 -s -r -n 1
case $REPLY in
q) done=true; if [ -n "$pid" ]; then kill $pid; fi;;
f) echo foo;;
esac
fi
if [ -n "$pid" ]; then
kill -0 $pid 2>&-
if [ $? -ne 0 ]; then
echo "$pid terminated"
wait $pid
pid=""
exec 3<&-
else
read -t 0.1 -u 3 -r
echo "reading from fd3: X${REPLY}X $?"
if [ -n "$REPLY" ]; then
echo "$REPLY"
fi
fi
fi
sleep 0.5
done
나 자신은 Python이 더 깔끔하고 "맞춤형"이지만 대부분의 경우 어느 쪽이든 수행할 수 있습니다.