명령이 실행된 후에도 Bash를 계속 실행하는 방법은 무엇입니까?

명령이 실행된 후에도 Bash를 계속 실행하는 방법은 무엇입니까?

나는 다음과 같은 것을 실행하고 싶습니다 :

bash -c "some_program with its arguments"

그러나 대화형 bash가 some_program종료된 후에도 계속 실행되도록 하십시오.

-c나는 이것이 좋은 접근 방식이 아니라고 확신합니다 man bash.

대화형 쉘은 옵션이 아닌 인수와 -c 옵션 없이 시작됩니다.

그럼 어떻게 해야 할까요?

설명된 주요 목표여기

노트

  • some_program수시로 종료 해야 해요
  • 배경에 넣고 싶지 않아요
  • bash난 남아서 다른 일을 하고 싶어
  • 프로그램을 다시 실행하고 싶습니다.

답변1

다음은 원하는 작업을 수행하는 더 짧은 솔루션이지만 문제와 bash 작동 방식을 이해하지 않으면 의미가 없을 수 있습니다.

bash -i <<< 'some_program with its arguments; exec </dev/tty'

그러면 bash 쉘이 시작 some_program되고 종료 시 some_program대화형 쉘이 시작됩니다.

기본적으로 우리가 하는 일은 bash의 STDIN에 문자열을 입력하는 것입니다. 이 문자열은 bash에게 시작 some_program하고 실행하라고 지시합니다 exec </dev/tty. exec </dev/ttyBash에게 우리가 제공한 문자열에서 STDIN을 전환하도록 지시하여 /dev/tty대화형으로 만듭니다.

이는 -ibash가 시작될 때 STDIN이 tty인지 확인하지만 bash가 시작될 때는 그렇지 않기 때문입니다. 하지만 앞으로는 그렇게 할 것이므로 bash를 대화형 모드로 강제 전환합니다.


또 다른 솔루션

제가 생각하기에 이식성이 매우 좋은 또 다른 아이디어는 파일 끝에 다음을 추가하는 것입니다 ~/.bashrc.

if [[ -n "START_COMMAND" ]]; then
  start_command="$START_COMMAND"
  unset START_COMMAND
  eval "$start_command"
fi

그런 다음 먼저 명령으로 쉘을 시작하려면 다음을 수행하십시오.

START_COMMAND='some_program with its arguments' bash

설명하다:

대부분은 분명하지만 변수 이름이 변경되는 이유는 변수를 지역화할 수 있기 때문입니다. 변수가 내보내지기 때문에 $START_COMMAND쉘의 모든 하위 항목에 의해 상속되며, 다른 bash 쉘이 이러한 하위 항목 중 하나인 경우 명령을 다시 실행합니다. 따라서 내보내지 않은 새 변수( $start_command)에 값을 할당하고 이전 변수를 삭제합니다.

답변2

( exec sh -i 3<<SCRIPT 4<&0 <&3                                        ⏎
    echo "do this thing"
    echo "do that thing"
  exec  3>&- <&4
  SCRIPT
)

이는 스크립트를 통해 수행하는 것이 가장 좋습니다. exec $0.또는 이러한 파일 설명자 중 하나가 현재 사용되지 않는 터미널 장치를 가리키는 경우 도움이 됩니다. 다른 프로세스도 해당 터미널을 확인하려고 한다는 점을 기억해야 합니다.

그런데, 내가 가정한 대로 스크립트를 실행한 후 환경을 보존하는 것이 목표라면 아마도 더 나은 서비스를 받을 수 있을 것입니다.

. ./script

.dotbash's source동일하지 않습니다. 쉘은 .dotPOSIX가 특수 쉘 내장으로 지정되었으므로 가능한 한 가깝다는 것이 보장되지만 이것이 거기에 있다는 보장은 아닙니다.

위의 내용은 예상한 대로이지만 잘못된 것은 없습니다. 예를 들어 다음을 수행할 수 있습니다.

 ( exec sh -i 3<<SCRIPT 4<&0 <&3                                        ⏎
    echo "do this thing"
    echo "do that thing"
    $(cat /path/to/script)
    exec  3>&- <&4
    SCRIPT
 )

exit쉘은 스크립트를 실행하고 대화형 프롬프트로 돌아갑니다. 즉, 스크립트 내에서 쉘을 호출 하지 않는 한 , 즉 프로세스를 백그라운드에 두는 한, 이는 i/o를 다음으로 연결합니다./dev/null.

데모:

% printf 'echo "%s"\n' "These lines will print out as echo" \
    "statements run from my interactive shell." \
    "This will occur before I'm given the prompt." >|/tmp/script
% ( exec sh -i 3<<SCRIPT 4<&0 <&3
    echo "do this thing"
    echo "do that thing"
    $(cat /tmp/script)
    exec  3>&- <&4
SCRIPT
)
sh-4.3$ echo "do this thing"
    do this thing
sh-4.3$ echo "do that thing"
    do that thing
sh-4.3$ echo "These lines will print out as echo"
    These lines will print out as echo
sh-4.3$ echo "statements run from my interactive shell."
    statements run from my interactive shell.
sh-4.3$ echo "This will occur before I'm given the prompt."
    This will occur before I'm given the prompt.
sh-4.3$ exec  3>&- <&4
sh-4.3$

많은JOBS

내 생각에는 여러분이 셸에 내장된 작업 관리 옵션에 더 익숙해져야 한다고 생각합니다. @Kiwy와 @jillagre는 이미 답변에서 이에 대해 다루었지만 더 자세한 내용이 필요할 수 있습니다. POSIX에 지정된 내장 특수 셸 하나를 언급했지만 더 많은 것이 set, jobs, fg,있고 bg다른 답변에서 알 수 있듯이 두 개가 더 trap있습니다 .kill

동시에 실행 중인 백그라운드 프로세스의 상태에 대한 즉각적인 알림을 아직 받지 못한 경우 이는 현재 셸 옵션이 POSIX 지정 기본값으로 설정되어 있기 때문 -m이지만 set -b다음을 사용하여 이러한 알림을 비동기적으로 받을 수 있습니다.

% man set
    −b This option shall be supported if the implementation supports the
         User  Portability  Utilities  option. It shall cause the shell to
         notify the user asynchronously of background job completions. The
         following message is written to standard error:
             "[%d]%c %s%s\n", <job-number>, <current>, <status>, <job-name>

         where the fields shall be as follows:

         <current> The  character  '+' identifies the job that would be
                     used as a default for the fg or  bg  utilities;  this
                     job  can  also  be specified using the job_id "%+" or
                     "%%".  The character  '−'  identifies  the  job  that
                     would  become  the default if the current default job
                     were to exit; this job can also  be  specified  using
                     the  job_id  "%−".   For  other jobs, this field is a
                     <space>.  At most one job can be identified with  '+'
                     and  at  most one job can be identified with '−'.  If
                     there is any suspended  job,  then  the  current  job
                     shall  be  a suspended job. If there are at least two
                     suspended jobs, then the previous job also shall be a
   −m  This option shall be supported if the implementation supports the
         User Portability Utilities option. All jobs shall be run in their
         own  process groups. Immediately before the shell issues a prompt
         after completion of the background job, a message  reporting  the
         exit  status  of  the background job shall be written to standard
         error. If a foreground job stops, the shell shall write a message
         to  standard  error to that effect, formatted as described by the
         jobs utility. In addition, if a job  changes  status  other  than
         exiting  (for  example,  if  it  stops  for input or output or is
         stopped by a SIGSTOP signal), the shell  shall  write  a  similar
         message immediately prior to writing the next prompt. This option
         is enabled by default for interactive shells.

Unix 기반 시스템의 매우 기본적인 특징은 프로세스를 처리하는 방식입니다 signals. 언젠가 기사를 읽었는데영감을 주는 기사피험자는 그 과정을 Douglas Adams의 지구 설명에 비유했습니다.무엇을 해야할지:

“은하수를 여행하는 히치하이커를 위한 안내서에서 Douglas Adams는 우울한 인간 집단과 인간의 허벅지를 깨물어 통신하는 날카로운 이빨을 가진 동물이 살고 있는 극도로 황량한 행성에 대해 설명합니다. 커널은 프로세스와 통신합니다. 마비 또는 치명적인 신호가 발생하면 프로세스는 일부 신호를 가로채서 상황에 적응하려고 시도할 수 있지만 대부분의 프로세스는 그렇지 않습니다."

이는 kill signals.

% kill -l 
> HUP INT QUIT ILL TRAP ABRT BUS FPE KILL USR1 SEGV USR2 PIPE ALRM TERM STKFLT CHLD CONT STOP TSTP TTIN TTOU URG XCPU XFSZ VTALRM PROF WINCH POLL PWR SYS

위의 인용문은 적어도 나에게는 많은 질문에 답해 줍니다. 예를 들어, 프로세스를 모니터링하려면 이렇게 dd해야 한다고 항상 생각했는데 kill, 이상하고 전혀 직관적이지 않습니다. 읽고 나면 말이 되는 것 같아요.

나는 그들 중 대부분을 말할 것입니다적응하려고 하지 마세요그리고 정당한 이유가 있습니다. 개발자가 중요하다고 생각하는 정보를 터미널에 스팸으로 보내는 여러 프로세스가 있으면 이점보다 더 많은 짜증을 유발할 수 있습니다.

터미널 구성에 따라 다름(당신은 확인할 수 있습니다 stty -a), 아마도 를 현재 포그라운드 프로세스 그룹 리더(아마도 쉘)로 CTRL+Z전달하도록 설정되어 있을 것이며 , 기본적으로 이를 알리고 마지막 명령을 일시 중단하도록 구성해야 합니다. 다시 말하지만, @jillagre와 @Kiwy의 답변에서 알 수 있듯이 이 기능을 목적에 맞게 원하는 대로 조정할 수 있습니다.SIGTSTPtrap

SCREEN JOBS

따라서 이러한 기능을 활용하려면 먼저 해당 기능을 이해하고 필요에 따라 처리 방법을 사용자 정의해야 합니다. 예를 들어, 방금 발견했습니다.Github의 이 screenrc여기에는 screen다음 키 바인딩이 포함됩니다 SIGTSTP.

# hitting 'C-z C-z' will run Ctrl+Z (SIGTSTP, suspend as usual)
bind ^Z stuff ^Z

# hitting 'C-z z' will suspend the screen client
bind z suspend

이렇게 하면 자식 프로세스로 실행 중인 프로세스를 일시 중지 screen하거나 자식 프로세스 자체를 일시 중지하는 screen것이 간단해집니다 .

즉시 다음:

% fg  

또는:

% bg

원하는 대로 프로세스를 포그라운드 또는 백그라운드에 배치합니다. 내장된 기능은 jobs언제든지 이러한 목록을 제공할 수 있습니다. add -l피연산자에는 pid 세부정보가 포함됩니다.

답변3

이렇게 하면 트릭을 수행할 수 있습니다.

bash -c "some_program with its arguments;bash"

편집하다:

새로 업데이트된 시도는 다음과 같습니다.

bash -c "
trap 'select wtd in bash restart exit; do [ \$wtd = restart ] && break || \$wtd ; done' 2
while true; do
    some_program with its arguments
done
"
  • 때때로 some_program을 종료해야 합니다

를 사용하면 ControlC다음과 같은 작은 메뉴가 표시됩니다.

1) bash
2) restart
3) exit
  • 배경에 넣고 싶지 않아요

그게 다야.

  • 계속 파티하고 싶고 다른 일도 하고 싶어

"bash" 옵션을 선택하세요

  • 프로그램을 다시 실행하고 싶습니다.

"다시 시작" 옵션을 선택하세요

답변4

$ bash --init-file <(echo 'some_program with its arguments')
$ bash --rcfile <(echo 'some_program with its arguments')

프로세스 대체를 사용할 수 없는 경우:

$ cat script
some_program with its arguments
$ bash --init-file script

그리고 sh( dash, busybox):

$ ENV=script sh

또는:

$ bash -c 'some_program with its arguments; exec bash'
$ sh -c 'some_program with its arguments; exec sh'

관련 정보