2017-03-16 4 views
0

이것은 아주 순진하지만 나는 그것을 한 번 줄 것이다.
나는 bush에서 gimp -i -b - &으로 gimp를 시작한 다음 무한 루프에서 dbus 신호를 읽고이 신호에서 얻은 데이터를 gimp로 보내주었습니다. gimp -i -b -은 명령 줄 gimp를 시작하고 gnuplot 등의 사용자 입력을 기다리고 있습니다. 그러나 명령 실행 후 bash에서 stdin에 액세스 할 수 있습니까?Bash가 출시 된 후 백그라운드 작업의 stdin에 쓰기

이상적으로 일에 그런 일을하려는 모든 gimp cmd &이 같은 김프 인스턴스로 전송됩니다

gimp -i -b - & 

dbus-monitor --profile "..." --monitor | 
while read -r line; do 
gimp -b '(mycommand '$line')' & 
done 

gimp -b '(gimp-quit 0)' & 

. 길어서 사용하지 않고 필요할 때 다시 시작하면 gimp 인스턴스를 닫을 수 있다면 더 좋을 것입니다.

일부 데몬 응용 프로그램을 작성하지 않고 bash로 가능합니까?

답변

4

간단한 해결책

간단한 파이프로 만들 수 있습니다. 김프로 출력을 파이프하면서 그 기능을 함수로 스크립트의 명령 전송 부분을 감싸고 전화 :

#! /bin/bash 

sendCommands() { 
    dbus-monitor --profile "..." --monitor | 
    while read -r line; do 
     echo "(mycommand $line)" 
    done 
    echo "(gimp-quit 0)" 
} 

sendCommands | gimp -i & 

sendCommandsgimp -i가 병렬로 실행됩니다. sendCommands이 무언가를 프린트 할 때마다, 그 무언가는 김프의 표준 입력에 도착할 것입니다.
전체 스크립트 인 경우 gimp -i 뒤에 &을 생략 할 수 있습니다. 나는 그것을 충분히 오랫동안 사용되어 있지 않은 경우 김프 인스턴스를 닫고 필요할 때 다시 시작할 수 있다면

죽이고 다시 시작 김프

더 나은 것입니다.

이것은 일부 이미지를 처리하는 동안 김프를 죽이지 않으므로 timeout 명령을 사용하는 것보다 약간 복잡합니다. 또한 이벤트 소비와 해당 명령 전송 사이에 sendCommands을 삭제하지 않으려합니다.

아마도 60 초마다 dbus 이벤트를 보내도록 도우미 프로세스를 시작할 수 있습니다. 이 이벤트를 tick이라고합시다. 진드기도 sendCommands에 의해 읽혀집니다. 그 사이에 명령이없는 두 개의 틱이 있으면 김프를 죽여야합니다.

김프에 명령을 보내기 위해 FIFO (named pipes)를 사용합니다. 새로운 김프 프로세스가 시작될 때마다 새로운 FIFO도 생성됩니다. 이렇게하면 새로운 김프 프로세스를 목표로하는 명령도 새 프로세스로 전송됩니다. 김프가 60 초 이내에 대기중인 작업을 완료 할 수없는 경우 동시에 두 번의 김프 프로세스가있을 수 있습니다. dbus-monitor ... | while ... done 지금 while ... done < <(dbus-monitor ...)로 작성되어

#! /bin/bash 

generateTicks() { 
    while true; do 
     # send tick over dbus 
     sleep 60 
    done 
} 

generateTicks & 

gimpIsRunning=false 
wasActive=false 
sleepPID= 
fifo= 

while read -r line; do 
    if eventIsTick; then # TODO replace "eventsIsTick" with actual code 
     if [[ "$wasActive" = false ]]; then 
      echo '(gimp-quit 0)' > "$fifo" # gracefully quit gimp 
      gimpIsRunning=false 
      [[ "$sleepPID" ]] && kill "$sleepPID" # close the FIFO 
      rm -f "$fifo" 
     fi 
     wasActive=false 
    else 
     if [[ "$gimpIsRunning" = false ]]; then 
      fifo="$(mktemp -u)" 
      mkfifo "$fifo" 
      sleep infinity > "$fifo" & # keep the FIFO open 
      sleepPID="$!" 
      gimp -i < "$fifo" & 
      gimpIsRunning=true 
     fi 
     echo "(mycommand $line)" > "$fifo" 
     wasActive=true 
    fi 
done < <(dbus-monitor --profile "..." --monitor) 

echo '(gimp-quit 0)' > "$fifo" # gracefully quit gimp 
[[ "$sleepPID" ]] && kill "$sleepPID" # close the FIFO 
rm -f "$fifo" 

참고. 두 버전 모두 dbus의 출력에 대해 루핑한다는 측면에서 동일한 작업을 수행하지만 파이프가있는 버전 |은 루프 내부에 전역 변수를 설정할 수없는 서브 쉘을 만듭니다. 자세한 설명은 SC2031을 참조하십시오.

+0

감사합니다. @Socowi, 훌륭한 답변입니다.난 그냥 2 노트를 추가 할 수 있습니다 : 첫째로 나는 실수를했습니다. 그것은 김프를 실행하고 표준 입력으로부터 사용자 입력을 기다리고있는'gimp -i'뿐만 아니라'gimp -i -b -'입니다. 둘째, 대답의 마지막 부분은 김프뿐만 아니라 일반 앱에도 적합합니다. 그러나 김프의 경우 우리는 하나의 장점을 가지고 있습니다.'(gimp-message (문자열 추가) "처리가 완료되었습니다!))'로 stderr에 경고를 인쇄 할 수 있습니다. 그래서 우리는 김프가 유휴 모드에 있다는 사실을 알려주도록 강제 할 수 있습니다. – truf

+0

나는 sendCommands와 같은 것을 실행할 수 있어야한다고 생각한다. gimp -i -b-3> & 1 1> & 2 2> & 3 | processReply &'와 process에 대한 grep 메시지는'processReply()'에서 끝납니다. 따라서'gimpIsRunning'을 통해'gimpIsWorking' 글로벌 변수를 가변적으로 사용할 수 있어야하고'timeout' 접근법을 고수 할 수 있어야합니다. 물론 그러한 접근은 김프만으로 가능하고 일반적인 경우는 아닙니다. 결과 코드가이 경우 더 간단 해지는지 궁금합니다. – truf

+0

좋은 지적. 불행히도 gimp의 stderr를 검사 할 때 상황이 훨씬 단순하지 않습니다. 우리는 미리 타임 아웃을 알지 못하기 때문에 (그것은 미래의 들어오는 작업에 달려있다.)'timeout'은 여전히 ​​유용하지 않다. 'sendCommands | 김프 ... | processReply &'도 사용할 수 없습니다. 우리는 파이프 라인의 중간에있는 김프 프로세스를 중지하고 새로운 김프 프로세스로 대체 할 수 없습니다. 김프의 표준 오류를 검사 할 때만 얻을 수있는 이점 : 우리는 한 번에 한 번의 김프 프로세스 만 실행할 수 있습니다. – Socowi