Bash 스크립트가 어떻게 실행되었는지 알 수 있습니까?


10

에코 및 읽기를 통해 나에게 묻는 작은 변경 사항으로 다소 복잡한 명령을 실행하도록 돕기 위해 Bash 스크립트를 만들려고했습니다.

명령을 실행하기 위해 터미널을 강제로 실행하는 솔루션을 찾았지만 관심이 없습니다. 내가 원하는 것은 노틸러스에서 실행하고 Enter 키를 누르면 (실행 소프트웨어로 실행) "터미널에서 실행하십시오"라는 알림이 표시됩니다.

명령을 알고있는 것처럼 팝업이 발생할 수는 있지만 Bash 스크립트가 터미널 내에서 실행되고 있는지 여부를 알 수 없으므로 항상 그렇게 생각하는 것 같습니다. 가능합니까?

답변:


10

에서 man bash아래 조건식 :

-t fd  
    True if file descriptor fd is open and refers to a terminal.

fd 1이 표준이라고 가정하면 if [ -t 1 ]; then효과가 있습니다. 고급 쉘 스크립팅 가이드의 주장 -t이 방법을 사용이 끝난 실패 ssh하고 테스트하는 것이 (표준 입력을 사용하지 표준 출력)을 따라서해야한다 :

if [[ -t 0 || -p /dev/stdin ]]

-p파일이 존재하고 명명 된 파이프인지 테스트합니다. 그러나 경험적으로 이것은 나에게 해당되지 않습니다. -p /dev/stdin일반 터미널과 ssh 세션 모두에서 실패하지만 두 경우 모두에서 작동합니다 if [ -t 0 ](또는 고급 쉘 스크립팅 안내서-t 1 의 해당 섹션에서 문제에 대한 아래 Gilles 의견 참조 ).


주요한 문제가 해당 컨텍스트에 적합한 방식으로 동작하도록 스크립트를 호출하려는 특수한 컨텍스트 인 경우 래퍼 및 사용자 정의 변수를 사용하여 이러한 모든 기술을 회피하고 약간의 소란을 피할 수 있습니다.

!#/bin/bash

export SPECIAL_CONTEXT=1
/path/to/real/script.sh

이것을 호출 live_script.sh하거나 대신 두 번 클릭하십시오. 물론 명령 줄 인수를 사용하여 동일한 작업을 수행 할 수 있지만 GUI 파일 브라우저에서 작업을 수행하고 클릭하려면 래퍼가 여전히 필요합니다.


5
이것이 정답입니다. POSIX는 쉘이 대화식인지 아닌지를 감지해야한다고 말합니다.
mikeserv

2
@DanielAmaya-입력을 리디렉션하면 터미널에서 스크립트가 실행되고 있지 않습니다. 문제는 스크립트가 터미널에서 실행되고 있는지 감지하는 방법입니다.
mikeserv

2
당신의 사용에 대한 확신 ||에서 [ … ]그런? 사용 [[ … ]]하면 문제가 없지만 일반적으로 ||는 명령을 구분하는 데 사용되며 마지막 이 없기 때문에 [ -t 0잘못 호출됩니다 . 일반적으로 명령도 없습니다. 터미널 테스트에 동의합니다. 아마도 그렇게하는 방법 일 것입니다. 그것은 내가 관심있는 구문 일뿐입니다. []-p
Jonathan Leffler

1
@JonathanLeffler 오른쪽; 쉘 연산자 ||가에 필요한 최종 ]인수 앞에 표시 되므로 구문 오류가 발생 합니다 [.
chepner

3
Advanced Bash-Scripting Guide의 해당 섹션에는 몇 가지 오류가 있습니다. PS1쉘이 대화식인지 여부를 확인하기위한 신뢰할 수있는 테스트가 아닙니다. “대화식 쉘에서 스크립트가 실행 중인지 테스트해야하는 경우”도 혼동됩니다. 일부 코드 를 테스트 해야 할 경우 스크립트는 일반적으로 대화식 쉘에서 실행되고 있지 않습니다 (하지만 소스 인 경우 가능) . 에 대한 테스트 i에서 것은 $-쉘이 상호 작용하는 경우 테스트에 대한 올바른 방법입니다. 테스트 -t 0또는하는 -t 2스크립트가 상호 작용하는 것으로 다른 터미널에서 실행되고 있는지 알 수있는 올바른 방법입니다.
Gilles 'SO- 악마 그만해

0

쉘 중첩 수준을 감지하려면 bash $ SHLVL 변수를 사용하십시오. 스크립트를 두 번 클릭하여 'raw'를 실행하면 1이되고 터미널 내에서 실행되는 스크립트는 2가됩니다.

#!/bin/bash
if (( SHLVL < 2 )) ; then
    echo "Please run this from a terminal."
    read -p "Press <Enter> to close this window"
    exit 1
fi
# rest of script

0

goldilocks의 대답은 일반적인 경우에 맞을지 모르지만 가장자리가있는 것처럼 보입니다. 내 경우에는 내 xserver가 시작되도록 구성되어 tty1있으며 tty를 떠나지 않습니다. Xorg stdout가 TTY 인 경우 클라이언트는 기본적으로 해당 TTY를 파일 디스크립터에 링크 한 것으로 보입니다.

내 문제를 해결 한 방법은 다음과 같습니다.

#!/bin/bash
isxclient=$( readlink /dev/fd/2 | grep -q 'tty' && [[ -n $DISPLAY ]] ; echo $? )
if [[ ! -t 2  || $isxclient == "0" ]]; then
        notify-send "Script wasn't started from an interactive shell"
else
        echo "Script was started from an interactive shell"
fi

더 표준 X 구성에서 작동하는지 확인하기 위해 이것을 테스트하지 않았으며 이것이 유일한 경우인지 의심합니다. 더 일반적으로 적용 가능한 해결책을 찾는 사람이 있으면 다시 와서 알려주십시오.


-2

다른 하나는 bash 옵션을 사용하여 내부 변수를 설정합니다 $-.

에서 .bashrc,

# If not running interactively, don't do anything
case $- in
    *i*) ;;
    *) return;;
esac

대화식 쉘은 반드시 터미널에 연결될 필요는 없다. 해당 연결로 시작된 것이 자동으로 대화식으로 시작되는 동안 가능합니다 cmd | sh -i | cmd.
mikeserv

이 코드는 스크립트에서 실행 중입니다. 터미널에서 실행 되더라도 대화식이 아닙니다.
Gilles 'SO- 악마 그만해
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.