셸에서 애플리케이션을 "올바르게" 시작하는 방법

셸에서 애플리케이션을 "올바르게" 시작하는 방법

이 질문을 정확하게 표현하기는 어렵지만 최선을 다하겠습니다. 나는 그것을 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?

답변1

프로그램을 실행하고 터미널에서 분리하는 방법에는 여러 가지가 있습니다. 하나는 백그라운드에서 실행하는 것입니다.서브쉘, 다음과 같이( firefox좋아하는 프로그램으로 교체):

(firefox &)

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

firefox & disown firefox

애플리케이션 런처 작동 방식이 궁금하신 경우 dmenu바이너리 1개와 셸 스크립트 2개( dmenu, , dmenu_path) 를 제공해 주세요 dmenu_run.

dmenu_run의 출력을 dmenu_pathdmenu로 파이프하면 $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 "$@") &

답변2

나는 G-Man의 답변을 정말 좋아합니다. 하지만 귀하의 우려가 혼란스러울 것 같아 답변을 드립니다. Wayne이 지적했듯이 가장 좋은 대답은 "원하는 결과를 얻는 것이 무엇이든"입니다.

Unix 프로세스 관리에서 각 프로세스에는 상위 프로세스가 있습니다. 유일한 예외는 init시작 시 운영 체제에 의해 시작되는 프로세스입니다. 부모 프로세스가 종료될 때 모든 자식 프로세스를 가져가는 것은 정상적인 동작입니다. 이는 모든 하위 프로세스에 SIGHUP 신호를 전송하여 수행됩니다. SIGHUP의 기본 처리는 프로세스를 종료합니다.

사용자 프로세스에 대한 쉘 생성은 작성한 코드와 다르지 않습니다.포크(2)/실행(3)원하는 언어로 전화하세요. 셸은 상위 프로세스이며, 셸이 종료되면(예: 로그아웃) 생성된 하위 프로세스도 마찬가지입니다. 설명하는 미묘한 차이점은 해당 동작을 수정하는 방법일 뿐입니다.

exec /path/to/program전화를 거는 것처럼실행(3). 예, program상위 실행 쉘을 유지하면서 쉘을 으로 대체합니다 .

sh -c /path/to/program.program/path/to/program​( sh /path/to/script.sh하위 쉘에서 실행 권한이 부족한 쉘 스크립트를 실행하는 데 사용할 수 있음)

/path/to/program"포그라운드" 프로세스를 생성합니다. 즉, 쉘은 다른 작업을 수행하기 전에 프로세스가 완료될 때까지 기다립니다. 시스템 호출 컨텍스트에서는 다음과 같습니다.포크(2)/실행(3)/프로세스를 기다리는 중(2). 하위 프로세스는 상위 프로세스로부터 stdin/stdout/stderr을 상속받습니다.

/path/to/program &(리디렉션 무시) "백그라운드 프로세스"를 만듭니다. 프로세스는 여전히 셸의 하위 프로세스이지만 상위 프로세스는 프로세스가 종료될 때까지 기다리지 않습니다.

nohup /path/to/program옮기다노스햅(1)program제어 터미널이 닫혀 있으면 SIGHUP이 전송되지 않도록 합니다. 전경 또는 배경 중 하나는 옵션입니다(대부분 프로세스가 배경에 있음에도 불구하고). nohup.out다른 방식으로 표준 출력을 리디렉션하지 않으면 이는 단지 출력일 뿐입니다.

프로세스를 백그라운드에 넣을 때 상위 프로세스가 종료되면 두 가지 중 하나가 발생합니다. 부모라면제어 터미널, 그러면 SIGHUP이 어린이에게 전송됩니다. 그렇지 않은 경우 프로세스는 "고아"가 되어 init프로세스에 의해 상속될 수 있습니다.

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

하지만 프로세스 관리와 관련된 특정 문제를 해결하지 않는 한 쉘, 서브쉘 또는 하위 프로세스의 프로세스 생성에 신경써서는 안 된다고 생각합니다.

답변3

글쎄요, 당신은 이 점을 잘 이해하고 있는 것 같습니다. 당신이 가지고 있는 것 중 일부를 명확히 하기 위해,

  • sh -c /path/to/Program매우 유사하다

    $
    %/경로/대상/프로그램
    %Ctrl+D                             (또는 "출구")
    $

    그 안에서 새 셸 프로세스를 시작하고, 새 셸의 응용 프로그램 명령 경로를 제공하고, 새 셸이 종료되도록 합니다. 설명을 위해 새 셸이 다른 프롬프트를 제공한다는 점을 보여 드렸습니다. 이는 실제 생활에서는 발생하지 않을 수 있습니다. 이 구조는 여러 명령을 단일 명령처럼 보이도록 패키지로 래핑하거나(이름이 지정되지 않은 일회성 스크립트와 유사) 쉘 변수에서 복잡한 명령을 작성하는 등 까다로운 작업을 수행하는 데 가장 유용합니다. 간단한 매개변수를 사용하여 단일 프로그램을 실행하는 데에는 거의 사용하지 않을 것입니다.sh -c "command"

  • 2>&1표준 오류를 표준 출력으로 리디렉션합니다. 이는 별로 중요하지 않습니다 &. 대신 명령이 화면에 오류 메시지를 보낼 때 파일에 오류 메시지를 캡처하고 싶어도 사용할 수 있습니다.command > file
  • 출력 nohup.outnohup. 주요 목적은 비동기식으로 실행하고(종종 "백그라운드에서", 즉 "셸 독립 프로세스"라고 함) 실행하는 경우 계속 실행할 수 있는 가능성이 더 높도록 구성하는 것입니다. 명령이 여전히 실행 중인 동안(예: 로그아웃) 쉘을 종료합니다.nohup command &command

bash(1)그리고배쉬 참조 매뉴얼 좋은 정보원이다.

관련 정보