쉘에서 어플리케이션을“올바로”시작하는 방법


21

질문을 정확하게 표현하기는 어렵지만 최선을 다하겠습니다. 내가 사용하는 dwm내 기본 창 관리자로 및dmenu내 응용 프로그램 실행기로. 브라우저 외에 GUI 응용 프로그램을 거의 사용하지 않습니다. 내 작업의 대부분은 명령 줄에서 직접 수행됩니다. 또한, 나는 운영 체제, 응용 프로그램 등에 관한 미니멀리즘의 열렬한 팬입니다. 내가 제거하지 못한 도구 중 하나는 응용 프로그램 실행기였습니다. 주로 애플리케이션 런처의 작동 방식 / 동작에 대한 정확한 이해가 부족하기 때문입니다. 광범위한 인터넷 검색조차도 모호한 설명 만 표시합니다. 내가 실제로하고 싶은 것은 실제로 응용 프로그램을 생성하는 것 외에는 절대 사용하지 않기 때문에 응용 프로그램 시작 관리자를 제거하는 것입니다. 이를 위해 쉘에서 응용 프로그램을 "올바르게"시작하는 방법을 알고 싶습니다. "올바로"의 의미는 "응용 프로그램 실행기와 같은"방식으로 근사 할 수 있습니다.

쉘에서 프로세스를 생성하는 다음 방법에 대해 알고 있습니다.

  1. exec /path/to/Program 새로운 프로세스를 생성하지 않고 지정된 명령으로 쉘을 교체
  2. sh -c /path/to/Program 쉘 종속 프로세스 시작
  3. /path/to/Program 쉘 종속 프로세스 시작
  4. /path/to/Program 2>&1 & 쉘 독립 프로세스 시작
  5. nohup /path/to/Program & 쉘 독립 프로세스를 시작하고 출력을 nohup.out

업데이트 1 : dmenu반복 호출 ps -efl에서 다른 조건 으로 재구성하는 것, 예를 들어 설명 할 수 있습니다 . 새로운 쉘을 만들고이 쉘 /bin/bash의 자식으로 응용 프로그램을 /path/to/Program만듭니다. 아이가 주변에있는 한 껍질이 주변에있을 것입니다. (이것을 관리하는 방법은 저쪽에 있습니다 ...) 반대로 nohup /path/to/Program &쉘에서 발행 /bin/bash하면 프로그램은이 쉘의 자식이되지만이 쉘을 종료하면 프로그램의 부모가 최상위 프로세스가됩니다. 따라서 첫 번째 프로세스가 예 /sbin/init verbose이고 프로세스가 있으면 PPID 1프로그램의 상위 프로세스가 됩니다. 저는 여기에 그래프를 사용하여 설명하려 내용은 다음과 같습니다 chromium통해 출시 된 dmenu, firefox사용 시작되었다 exec firefox & exit:

systemd-+-acpid
        |-bash---chromium-+-chrome-sandbox---chromium-+-chrome-sandbox---nacl_helper
        |                 |                           `-chromium---5*[chromium-+-{Chrome_ChildIOT}]
        |                 |                                                    |-{Compositor}]
        |                 |                                                    |-{HTMLParserThrea}]
        |                 |                                                    |-{OptimizingCompi}]
        |                 |                                                    `-3*[{v8:SweeperThrea}]]
        |                 |-chromium
        |                 |-chromium-+-chromium
        |                 |          |-{Chrome_ChildIOT}
        |                 |          `-{Watchdog}
        |                 |-{AudioThread}
        |                 |-3*[{BrowserBlocking}]
        |                 |-{BrowserWatchdog}
        |                 |-5*[{CachePoolWorker}]
        |                 |-{Chrome_CacheThr}
        |                 |-{Chrome_DBThread}
        |                 |-{Chrome_FileThre}
        |                 |-{Chrome_FileUser}
        |                 |-{Chrome_HistoryT}
        |                 |-{Chrome_IOThread}
        |                 |-{Chrome_ProcessL}
        |                 |-{Chrome_SafeBrow}
        |                 |-{CrShutdownDetec}
        |                 |-{IndexedDB}
        |                 |-{LevelDBEnv}
        |                 |-{NSS SSL ThreadW}
        |                 |-{NetworkChangeNo}
        |                 |-2*[{Proxy resolver}]
        |                 |-{WorkerPool/1201}
        |                 |-{WorkerPool/2059}
        |                 |-{WorkerPool/2579}
        |                 |-{WorkerPool/2590}
        |                 |-{WorkerPool/2592}
        |                 |-{WorkerPool/2608}
        |                 |-{WorkerPool/2973}
        |                 |-{WorkerPool/2974}
        |                 |-{chromium}
        |                 |-{extension_crash}
        |                 |-{gpu-process_cra}
        |                 |-{handle-watcher-}
        |                 |-{inotify_reader}
        |                 |-{ppapi_crash_upl}
        |                 `-{renderer_crash_}
        |-2*[dbus-daemon]
        |-dbus-launch
        |-dhcpcd
        |-firefox-+-4*[{Analysis Helper}]
        |         |-{Cache I/O}
        |         |-{Cache2 I/O}
        |         |-{Cert Verify}
        |         |-3*[{DOM Worker}]
        |         |-{Gecko_IOThread}
        |         |-{HTML5 Parser}
        |         |-{Hang Monitor}
        |         |-{Image Scaler}
        |         |-{JS GC Helper}
        |         |-{JS Watchdog}
        |         |-{Proxy R~olution}
        |         |-{Socket Thread}
        |         |-{Timer}
        |         |-{URL Classifier}
        |         |-{gmain}
        |         |-{localStorage DB}
        |         |-{mozStorage #1}
        |         |-{mozStorage #2}
        |         |-{mozStorage #3}
        |         |-{mozStorage #4}
        |         `-{mozStorage #5}
        |-gpg-agent
        |-login---bash---startx---xinit-+-Xorg.bin-+-xf86-video-inte
        |                               |          `-{Xorg.bin}
        |                               `-dwm-+-dwmstatus
        |                                     `-xterm---bash-+-bash
        |                                                    `-pstree
        |-systemd---(sd-pam)
        |-systemd-journal
        |-systemd-logind
        |-systemd-udevd
        |-wpa_actiond
        `-wpa_supplicant

업데이트 2 : 질문은 다음과 같이 요약 될 수 있습니다. 프로세스의 부모는 무엇이되어야합니까? 예를 들어 쉘이어야합니까 아니면 init프로세스 즉, PID 1?


3
귀하의 질문에 대한 간결한 대답은 "원하는 결과를 얻는 것이 무엇이든"입니다.
Wayne Werner

1
댕, 쓰레기-좋은 질문을합니다. 하지만 웨인이 코에 있다고 생각합니다-최신 편집에 대해 init-대답이 어쩌면? 그것은 당신이 그것과 대화 할 계획인지, 어떻게 init사용하는지, 데이터 채널이 어디에 있는지에 달려 있습니다. 일반적으로 물건은 잘 작동하는 경향이 있습니다 init. 어쨌든 일반적으로 프로세스를 데몬화할 때 init. 또는 작업 제어, 현재 쉘을 원할 경우.
mikeserv

하하하, 건배 @mikeserv; 오전 4시 37 분 여기 아침에 이미 오늘의 첫 웃음. 사실, 그 물건은 항상 어떻게 든 작동합니다. 나는 dmenu배운 것을 어떻게 제거 하고 제거 할 것인가. 나는 아주 쓸모가 exec /path/to/Program & exit있거나 찾을 /bin/bash -c /path/to/Program & exit수있다. 그러나 모든 메이크업 1init의 부모 Program만큼이 말이하고 기본 위반하지 않는 한 나와 함께 괜찮 *nix원칙을.
lord.garbage

@ lord.garbage-당신 때문인 exec &것 같습니다. 나는 보통 터미널에서 내 일을 ... 벤 크로 웰의 질문에서 사용하게 될 것입니다 . 나는 거기에 답이 있지만, 그들 모두는 매우 좋습니다. 어쨌든, 당신이 프로세스를 배경으로하고 그 부모가 다음과 같이 죽을 때 : sh -c 'cat & kill $$'당신은 그것을 고아하고, 결국에는 거두어집니다. 그것은 init의 일입니다-그래서 그들은 모두 그것에 빠지게됩니다.
mikeserv

아마도 더 간단한 질문은 다음과 같습니다 systemd--bash--chromium. 쉘에서 위의 프로세스 트리를 얻는 방법은 무엇입니까 ? 내가 시도하는 모든 방법은 궁극적으로 systemd--chromium쉘에서 파이어 폭스를 생성 할 때 다음과 같은 형식의 프로세스 트리로 이어질 것 입니다. 껍질은 어떻게 악마입니까? 터미널과 관련이 없습니다.
lord.garbage

답변:


7

글쎄, 당신은 그것을 잘 이해하는 것 같습니다. 당신이 가진 것의 일부를 명확히하기 위해,

  • sh -c /path/to/Program 상당히 유사하다

    $ sh 
    % / path / to / Program 
    % Ctrl+ D                             (또는 " exit "를 입력 할 수 있습니다 ) 
    $

    새 셸 프로세스를 시작하는 경우 새 셸에 대한 응용 프로그램 명령 경로를 제공 한 다음 새 셸을 종료합니다. 나는 설명을 위해 다른 프롬프트를주는 새로운 쉘을 보여 주었다. 이것은 아마도 현실에서는 일어나지 않을 것입니다. 이 구문은 여러 명령을 번들로 래핑하는 것과 같이 까다로운 작업을 수행하는 데 유용하므로 단일 명령 (일명 이름이 지정되지 않은 단일 스크립트의 일종) 또는 쉘 변수에서 복잡한 명령을 작성하는 것처럼 보입니다. 간단한 인수로 단일 프로그램을 실행하는 데는 거의 사용하지 않습니다.sh -c "command"

  • 2>&1표준 오류를 표준 출력으로 리디렉션하는 것을 의미합니다. 이것과는 실제로 관련이 없습니다 &. 대신, 명령 을하고 파일에서 오류 메시지를 캡처하려는 경우에도 명령이 화면에 오류 메시지를 보낼 때이를 사용 합니다.command > file
  • 출력을 nohup.out로 리디렉션하는 것은 사소한 부작용입니다 nohup. 의 주된 목적은 실행하는 것입니다 비동기 적으로 (일반적으로 알려진 "배경", 또는 같은 단어 사용 "독립적 인 공정 쉘 ')은 수있는 더 나은 기회가 있도록 경우 계속 실행하고 구성을 명령이 계속 실행되는 동안 쉘을 종료하십시오 (예 : 로그 아웃).nohup command &command

bash(1)그리고 수동 강타 참조 정보의 좋은 소스입니다.


7

프로그램을 실행하고 터미널에서 분리하는 몇 가지 방법이 있습니다. 하나는 다음 과 같이 subshell 의 배경에서 실행하는 것입니다 ( firefox좋아하는 프로그램으로 대체 하십시오).

(firefox &)

다른 하나는 프로세스를 제거하는 것입니다.

firefox & disown firefox

당신은 응용 프로그램 발사기 작업이 방법에 대한 호기심 경우 dmenu: 이진 1을 제공하고, 2 쉘 스크립트 dmenu, dmenu_path그리고 dmenu_run각각.

dmenu_run출력 dmenu_path을 dmenu로 파이프하고 $SHELL변수를 설정 한대로 파이프 합니다. 비어 있으면을 사용 /bin/sh합니다.

#!/bin/sh
dmenu_path | dmenu "$@" | ${SHELL:-"/bin/sh"} &

dmenu_path좀 더 복잡하지만 간단히 말해서 $PATH환경 변수 에 이진 목록을 제공하고 가능한 경우 캐시를 사용합니다.

#!/bin/sh
cachedir=${XDG_CACHE_HOME:-"$HOME/.cache"}
if [ -d "$cachedir" ]; then
        cache=$cachedir/dmenu_run
else
        cache=$HOME/.dmenu_cache # if no xdg dir, fall back to dotfile in ~
fi
IFS=:
if stest -dqr -n "$cache" $PATH; then
        stest -flx $PATH | sort -u | tee "$cache"
else
        cat "$cache"
fi

쉘에서 프로그램을 실행할 필요는 없습니다. dmenu_run쉘에 파이핑하지 않고을 쓰는 또 다른 방법 은 다음과 같습니다.

#!/bin/sh
$(dmenu_path | dmenu "$@") &

6

나는 G-Man의 대답을 많이 좋아합니다. 하지만 당신이 혼란스러워하고 있다고 생각하기 때문에 응답하고 있습니다. Wayne이 지적했듯이 가장 좋은 대답은 "원하는 결과를 얻는 것이 무엇이든"입니다.

유닉스 프로세스 관리에서 모든 프로세스에는 부모가 있습니다. 이에 대한 한 가지 예외 init는 부팅시 OS에 의해 시작되는 프로세스입니다. 부모 프로세스가 죽을 때 자식 프로세스를 모두 가져가는 것은 정상적인 동작입니다. 이는 SIGHUP 신호를 모든 하위 프로세스로 전송하여 수행됩니다. SIGHUP의 기본 처리는 프로세스를 종료합니다.

사용자 프로세스의 셸 생성은 원하는 언어로 fork (2) / exec (3) 호출 을 코딩 한 경우와 다르지 않습니다 . 쉘은 부모이고, 쉘이 종료되면 (예를 들어, 로그 오프), 그 자식 프로세스가 생성됩니다. 당신이 묘사하는 뉘앙스는 그 행동을 수정하는 방법 일뿐입니다.

exec /path/to/programexec (3) 호출하는 것과 같습니다 . 예, 쉘을 program시작한 상위 항목을 유지하면서 쉘을로 바꿉니다.

sh -c /path/to/program의 자식 프로세스를 생성하는 자식 쉘 프로세스를 무의식적으로 만듭니다 program. /path/to/program실제로 실행 가능한 파일이 아닌 일련의 스크립트 명령어 인 경우에만 유용 합니다. ( sh /path/to/script.sh열등한 쉘에서 실행 권한이없는 쉘 스크립트를 실행하는 데 사용할 수 있음)

/path/to/program"전경"프로세스를 작성합니다. 즉, 쉘은 다른 조치를 수행하기 전에 프로세스가 완료 될 때까지 대기합니다. 시스템 호출 컨텍스트에서 fork (2) / exec (3) / waitpid (2)와 같습니다 . 자식은 부모로부터 stdin / stdout / stderr를 상속받습니다.

/path/to/program &(리디렉션 무시) "백그라운드 프로세스"를 만듭니다. 프로세스는 여전히 셸의 자식이지만 부모는 프로세스가 종료되기를 기다리지 않습니다.

nohup /path/to/program제어 터미널이 닫혀있는 경우 SIGHUP을 보내지 않도록 nohup (1) 을 호출합니다 program. 포 그라운드 또는 백그라운드에 있는지 여부는 선택 사항입니다 (가장 일반적으로 프로세스는 백그라운드입니다). 주 nohup.out당신이 그렇지 않으면 표준 출력을 리디렉션하지 않는 경우에만 출력을합니다.

백그라운드에서 프로세스를 넣을 때 상위 프로세스가 종료되면 두 가지 중 하나가 발생합니다. 부모가 제어 터미널 인 경우 SIGHUP이 자식에게 전송됩니다. 그렇지 않은 경우 프로세스가 "분리 된"것일 수 있으며 init프로세스에 의해 상속됩니다 .

입 / 출력 / 오류를 재 지정하면 모든 프로세스에있는 파일 디스크립터를 상위 프로세스에서 상속 한 파일 디스크립터와 다른 파일에 연결하기 만하면됩니다. 이 중 어느 것도 프로세스 소유권이나 트리 깊이에 영향을 미치지 않습니다 (그러나 백그라운드 프로세스를 위해 터미널에서 3을 모두 리디렉션하는 것이 항상 의미가 있습니다).

모든 것을 말하지만, 프로세스 관리와 관련하여 해결해야 할 특정 문제가 없다면 쉘 또는 서브 쉘 또는 서브 프로세스에 의한 프로세스 생성에 대해서는 걱정하지 않아도됩니다.


nitpick : sh -c /path/to/program실행 비트가없는 경우 프로그램을 쉘 스크립트로 실행하지 않습니다 sh /path/to/program. sh -c /path/to/program쉘을 열고 해당 쉘 /path/to/program에서 명령으로 실행하면 실행 파일이 아닌 경우 실패합니다.
filbranden

글쎄, 우리가 nitpicking하는 경우, 우리 둘 다 잘못되었습니다. 쉘 sh -c /path/to/program에서 /path/to/program입력으로 명령을 읽습니다 . 파일에 실행 권한이 필요하지는 않지만 쉘 스크립트 여야합니다.
jwm

sh /path/to/program. 방금 직접 시도해 보았습니다 : echo echo hello world >abc.sh, sh ./abc.shprint hello world하면서 sh -c ./abc.sh말합니다 sh: ./abc.sh: Permission denied( ./abc.sh현재 쉘에서 직접 실행하는 것과 동일 합니다). (또는 어쩌면 나는 이전 의견에서 나 자신을 잘 표현하지 못했습니다 ...)
filbranden

내 잘못. 하위 쉘의 생성을 제외하고 명령 프롬프트에서 sh -c _something_입력하는 것과 동일 _something_합니다. 따라서 (파일로) 실행 비트가 누락되면 실패 할 것입니다. 반면에 일련의 쉘 명령을 제공 할 수 sh -c "echo hello world"있으며 정상적으로 작동합니다. 따라서 입력 한 내용에 실행 비트 (또는 파일)가 필요하지 않으며 쉘 인터프리터 만 사용할 수 있습니다.
jwm

OP가 컴파일 또는 시스템 실행 파일을 참조한다고 생각하므로 실행 권한이 가정되었습니다.
jwm
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.