현재 작업중인 쉘을 어떻게 확인할 수 있습니까?
ps
명령 의 출력 만으로도 충분합니까?
유닉스의 다른 풍미에서 어떻게 이것을 할 수 있습니까?
현재 작업중인 쉘을 어떻게 확인할 수 있습니까?
ps
명령 의 출력 만으로도 충분합니까?
유닉스의 다른 풍미에서 어떻게 이것을 할 수 있습니까?
답변:
현재 쉘의 실행 파일 이름 을 찾는 방법에는 세 가지가 있습니다 .
쉘의 실행 파일이 인 경우 세 가지 접근 방식을 모두 속일 수 /bin/sh
있지만 실제로는 이름이 바뀝니다 bash
(예 : 자주 발생).
따라서 ps
출력이 수행 될지 여부에 대한 두 번째 질문은 " 항상 "이 아닙니다 .
echo $0
-쉘의 경우 실제 쉘인 프로그램 이름을 인쇄합니다.
ps -ef | grep $$ | grep -v grep
-실행중인 프로세스 목록에서 현재 프로세스 ID를 찾습니다. 현재 프로세스는 쉘이므로 포함됩니다.
목록에 쉘의 프로세스 ID와 동일한 번호를 포함하는 다른 프로세스 가있을 수 있으므로 ps
, 특히 해당 ID가 작은 경우 (예 : 쉘의 PID가 "5"인 경우) 동일한 grep
출력 에서 "java5"또는 "perl5" !). 이것은 쉘 이름에 의존 할 수 없다는 점에서 "ps"접근 방식의 두 번째 문제입니다.
echo $SHELL
-현재 쉘의 경로는 쉘의 SHELL
변수 로 저장됩니다 . 이것에 대한주의 사항은 쉘을 서브 프로세스로 명시 적으로 시작하면 (예를 들어, 로그인 쉘이 아닌 경우) 로그인 쉘의 값을 대신 얻는다는 것입니다. 그럴 가능성이 있으면 ps
또는 $0
접근법을 사용하십시오 .
그러나 실행 파일이 실제 쉘과 일치하지 않으면 (예 : /bin/sh
실제로 bash 또는 ksh) 휴리스틱이 필요합니다. 다양한 쉘에 특정한 환경 변수는 다음과 같습니다.
$version
tcsh에 설정되어 있습니다
$BASH
bash에 설정되어 있습니다.
$shell
(소문자)는 csh 또는 tcsh에서 실제 쉘 이름으로 설정됩니다.
$ZSH_NAME
zsh에 설정되어 있습니다
KSH가 보유 $PS3
하고 $PS4
설정된 정상 반면 본 셸 ( sh
)만을 보유 $PS1
하고 $PS2
세트. 이것은 일반적으로 보인다 가장 어려운 구별하기 - 단지 사이에 환경 변수의 전체 세트의 차이 sh
와 ksh
우리는 솔라리스 회양목에 설치 한이다 $ERRNO
, $FCEDIT
, $LINENO
, $PPID
, $PS3
, $PS4
, $RANDOM
, $SECONDS
,와 $TMOUT
.
echo ${.sh.version}
반환 "나쁜 대체". 위의 내 솔루션보기
ps -ef | grep …
………처럼 100 % 신뢰할 수는 없습니다.” 간단한 정규 표현식을 사용 egrep
하거나 grep -e
모든 의도와 목적에 100 %까지 쉽게 신뢰성을 가져올 수 있습니다 ps -ef | egrep "^\s*\d+\s+$$\s+"
. ^
차종 확실히 우리가 줄의 처음부터 시작하고는 \d+
먹는 UID 최대의는 $$
PID를 일치하고 \s*
및 \s+
계정 및 대한 것은 다른 부분 사이의 공백을 보장합니다.
ps -ef | awk '$2==pid' pid=$$
ps -p $$
는 POSIX 옵션을 지원하는 유닉스 변형 ps -ef
과 관련된 솔루션과 다른 솔루션에서 작동해야 grep
하며 다른 곳에 나타날 수있는 일련의 자릿수를 grepping하여 오 탐지로 인해 발생하지 않습니다.ps
ps
이해할 -p
수 없으므로 사용해야 할 수도 있습니다 /bin/ps -p $$
.
$$
것을 제외하고 이해 fish
합니다 ps -p %self
.
/bin/ps
. ps
에 쉽게 설치할 수 있습니다 (실제로는 현재는 꽤 정상입니다) /usr/bin
. $(which ps) -p $$
더 나은 방법입니다. 물론 이것은 물고기와 다른 껍질에서는 작동하지 않습니다. 나는 그것이 (which ps) -p %self
물고기에 있다고 생각합니다 .
readlink /proc/$$/exe
sh
의해 에뮬레이트되는 bash
경우 ps -p는 다음 /usr/bin/bash
과 같이 실행하더라도sh
시험
ps -p $$ -oargs=
또는
ps -p $$ -ocomm=
ps -o fname --no-headers $$
.
test `ps -p $$ -ocomm=` == "bash" && do_something_that_only_works_in_bash
. (내 스크립트의 다음 줄은 csh와 동일합니다.)
-q
대신에 사용 합니다 -p
.SHELL=$(ps -ocomm= -q $$)
사용자가 Bash를 사용하여 스크립트를 호출하고 있는지 확인하려면 다음을 수행하십시오.
if [ ! -n "$BASH" ] ;then echo Please run this script $0 with bash; exit 1; fi
#!/bin/bash
: if [ ! -n "$BASH" ] ;then exec bash $0; fi
. 이 행을 사용하면 ksh 또는 sh를 사용하여 시작한 경우에도 bash를 사용하여 스크립트가 실행됩니다. 내 유스 케이스에는 명령 줄 인수가 필요하지 않지만 필요한 경우 추가 할 수 있습니다 $0
.
당신은 시도 할 수 있습니다:
ps | grep `echo $$` | awk '{ print $4 }'
또는:
echo $SHELL
/pattern/ { action }
를합니까?
$SHELL
환경 변수에는 현재 사용자의 기본값으로 구성된 셸이 포함되어 있습니다. 현재 실행중인 쉘을 반영하지 않습니다. 또한 ps -p $$
오 탐지 때문에 $$를 grepping 하는 것보다 사용하는 것이 좋습니다 .
awk
,ps | awk '$1=='$$' { n=split($4,a,"/"); print a[n] }'
다음은 항상 사용 된 실제 쉘을 줄 것이다 - 그것은 실제 실행 파일의 이름이 아닌 쉘 이름 (예 얻는 ksh93
대신 ksh
, 등). 의 경우 /bin/sh
, 실제 사용 된 쉘을 보여줍니다 dash
.
ls -l /proc/$$/exe | sed 's%.*/%%'
나는 ls
출력을 처리해서는 안된다고 말하는 많은 사람들이 있지만, 당신이 사용할 쉘을 특수 문자로 명명하거나 특수 문자로 명명 된 디렉토리에 배치 할 확률은 얼마입니까? 이 경우에도 여전히 다른 방식으로 수행하는 다른 예가 많이 있습니다.
Toby Speight가 지적한 것처럼 , 이것은 더 적절하고 깔끔한 방법으로 달성 할 수 있습니다.
basename $(readlink /proc/$$/exe)
/proc
. 모든 세계가 리눅스 박스는 아닙니다.
basename $(readlink /proc/$$/exe)
에 ls
+ sed
+ echo
.
ash -> /bin/busybox
나는 많은 다른 접근법을 시도했으며 가장 좋은 방법은 다음과 같습니다.
ps -p $$
Cygwin 에서도 작동 하며 PID grepping으로 오 탐지를 생성 할 수 없습니다. 약간의 청소를 통해 실행 가능한 이름 만 출력합니다 (Cygwin 아래 경로가 있음).
ps -p $$ | tail -1 | awk '{print $NF}'
기억하지 않아도되는 함수를 만들 수 있습니다.
# Print currently active shell
shell () {
ps -p $$ | tail -1 | awk '{print $NF}'
}
... 그리고 그냥 실행하십시오 shell
.
데비안과 Cygwin에서 테스트되었습니다.
ps
, tail
및 의 Windows 포트가 있더라도 gawk
cmd는 $$
PID로 정의하지 않으므로 일반 cmd에서는 확실히 작동하지 않습니다.
ps -p$$ -o comm=
않습니까? POSIX는 모든 헤더를 비우면 헤더를 완전히 억제한다고 말합니다. ps
직접 실행 된 스크립트 (예 :)로 소스를 제공 할 때 여전히 모든 답변 과 마찬가지로 실패 #!/bin/sh
합니다.
부모 프로세스 인쇄에 대한 나의 변형 :
ps -p $$ | awk '$1 == PP {print $4}' PP=$$
AWK가 대신 할 수있을 때 불필요한 응용 프로그램을 실행하지 마십시오.
awk
, 때 ps -p "$$" -o 'comm='
당신을 위해 그것을 할 수 있습니까?
쉘과 해당 버전을 찾는 방법에는 여러 가지가 있습니다. 나를 위해 일한 몇 가지가 있습니다.
똑바로
해시 접근
$> ******* (임의의 문자 세트를 입력하면 출력에 쉘 이름이 표시됩니다. 제 경우에는 -bash : chapter2-a-sample-isomorphic-app : command not found )
당신이 제공 /bin/sh
지원 POSIX 표준과 시스템이 가지고 lsof
에 대한 가능한 대안 - 설치 명령 lsof
이 경우 수 수 pid2path
- 당신은 또한 사용 (또는 적용) 할 수 인쇄 전체 경로가 다음 스크립트를 :
#!/bin/sh
# cat /usr/local/bin/cursh
set -eu
pid="$$"
set -- sh bash zsh ksh ash dash csh tcsh pdksh mksh fish psh rc scsh bournesh wish Wish login
unset echo env sed ps lsof awk getconf
# getconf _POSIX_VERSION # reliable test for availability of POSIX system?
PATH="`PATH=/usr/bin:/bin:/usr/sbin:/sbin getconf PATH`"
[ $? -ne 0 ] && { echo "'getconf PATH' failed"; exit 1; }
export PATH
cmd="lsof"
env -i PATH="${PATH}" type "$cmd" 1>/dev/null 2>&1 || { echo "$cmd not found"; exit 1; }
awkstr="`echo "$@" | sed 's/\([^ ]\{1,\}\)/|\/\1/g; s/ /$/g' | sed 's/^|//; s/$/$/'`"
ppid="`env -i PATH="${PATH}" ps -p $pid -o ppid=`"
[ "${ppid}"X = ""X ] && { echo "no ppid found"; exit 1; }
lsofstr="`lsof -p $ppid`" ||
{ printf "%s\n" "lsof failed" "try: sudo lsof -p \`ps -p \$\$ -o ppid=\`"; exit 1; }
printf "%s\n" "${lsofstr}" |
LC_ALL=C awk -v var="${awkstr}" '$NF ~ var {print $NF}'
-i
(-> 환경 무시) 옵션 이 사용 가능한지 env
확인하는 줄에 있기 때문에 bash에서 실패 lsof
합니다. 실패 : env -i PATH="${PATH}" type lsof
->env: ‘type’: No such file or directory
Bash (특정 버전)를 실행하고 있는지 확인하려면 $BASH_VERSINFO
배열 변수 를 사용하는 것이 가장 좋습니다 . (읽기 전용) 배열 변수는 환경에서 설정할 수 없으므로 현재 셸에서 오는지 확인할 수 있습니다.
그러나 Bash는로 호출 될 때 다른 동작 sh
을하기 때문에 $BASH
환경 변수가로 끝나는지도 확인해야합니다 /bash
.
내가 -
밑줄이 아닌 함수 이름을 사용 하고 연관 배열 (Bash 4에 추가)에 의존 하는 스크립트 에서 다음과 같은 위생 검사 (유용한 사용자 오류 메시지 포함)가 있습니다.
case `eval 'echo $BASH@${BASH_VERSINFO[0]}' 2>/dev/null` in
*/bash@[456789])
# Claims bash version 4+, check for func-names and associative arrays
if ! eval "declare -A _ARRAY && func-name() { :; }" 2>/dev/null; then
echo >&2 "bash $BASH_VERSION is not supported (not really bash?)"
exit 1
fi
;;
*/bash@[123])
echo >&2 "bash $BASH_VERSION is not supported (version 4+ required)"
exit 1
;;
*)
echo >&2 "This script requires BASH (version 4+) - not regular sh"
echo >&2 "Re-run as \"bash $CMD\" for proper operation"
exit 1
;;
esac
첫 번째 경우 기능에 대한 편집증 기능 검사를 생략하고 향후 Bash 버전이 호환 될 것이라고 가정 할 수 있습니다.
fish
쉘에 대한 답변 이 없습니다 (변수가 $$
없거나 $0
).
(에 테스트 나를 위해이 작품을 sh
, bash
, fish
, ksh
, csh
, true
, tcsh
,과 zsh
, 오픈 수세 13.2) :
ps | tail -n 4 | sed -E '2,$d;s/.* (.*)/\1/'
이 명령은과 같은 문자열을 출력합니다 bash
. 여기에만 사용하고 ps
, tail
그리고 sed
(GNU의 extesions하지 않고, 추가하려고 --posix
그것을 확인). 그것들은 모두 표준 POSIX 명령입니다. 나는 확실 tail
하게 제거 할 수 있지만 나의 sed
fu는 이것을하기에 충분히 강하지 않다.
이 솔루션은 OS X에서 작동하지 않으므로 이식성이 좋지 않습니다. :(
sed: invalid option -- 'E'
bash 3.2.51과 tcsh 6.15.00을 얻는다
내 해결책 :
ps -o command | grep -v -e "\<ps\>" -e grep -e tail | tail -1
다른 플랫폼과 셸에서 이식 가능해야합니다. 그것은 사용하는 ps
다른 솔루션처럼, 그러나 그것은에 의존하지 않는 sed
또는 awk
및 필터 배관에서 정크 밖으로 ps
자체가 너무 쉘은 항상 마지막 항목이되어야한다고. 이렇게하면 이식 불가능한 PID 변수에 의존하거나 올바른 행과 열을 선택할 필요가 없습니다.
Bash, Z shell ( zsh
) 및 fish (다른 PID 변수를 사용하기 때문에 물고기에 대한 표현을 변경하지 않고는 대부분의 솔루션에서 작동하지 않음 )를 사용하여 Debian 및 macOS에서 테스트 했습니다.
echo $$ # Gives the Parent Process ID
ps -ef | grep $$ | awk '{print $8}' # Use the PID to see what the process is.
grep $$
것은 신뢰할 수 없습니다. ps -ef | awk -v pid=$$ '$2==pid { print $8 }'
더 낫지 만 왜 사용하지 ps -p $$
않습니까?
Mac OS X (및 FreeBSD) :
ps -p $$ -axco command | sed -n '$p'
zsh
하고, 그것은 나에게 주었다 -bash
.
mutt
... : -b
"ps"출력에서 PID를 제거하는 것은 필요하지 않습니다. / proc 디렉토리 구조에서 PID에 대한 각 명령 행을 읽을 수 있기 때문입니다.
echo $(cat /proc/$$/cmdline)
그러나 그것은 단순히 다음보다 더 나을 수는 없습니다.
echo $0
이름이 나타내는 것과 실제로 다른 쉘을 실행하는 경우 한 가지 아이디어는 이전에 얻은 이름을 사용하여 쉘에서 버전을 요청하는 것입니다.
<some_shell> --version
sh
다른 사람들이 유용한 무언가를주는 동안 종료 코드 2로 실패하는 것처럼 보입니다 (그러나 내가 가지고 있지 않기 때문에 모든 것을 확인할 수는 없습니다).
$ sh --version
sh: 0: Illegal option --
echo $?
2
이것은 매우 깨끗한 솔루션은 아니지만 원하는 작업을 수행합니다.
# MUST BE SOURCED..
getshell() {
local shell="`ps -p $$ | tail -1 | awk '{print $4}'`"
shells_array=(
# It is important that the shells are listed in descending order of their name length.
pdksh
bash dash mksh
zsh ksh
sh
)
local suited=false
for i in ${shells_array[*]}; do
if ! [ -z `printf $shell | grep $i` ] && ! $suited; then
shell=$i
suited=true
fi
done
echo $shell
}
getshell
이제 사용할 수 있습니다 $(getshell) --version
.
그러나 이것은 KornShell 과 유사한 쉘 (ksh) 에서만 작동합니다 .
dash
, yash
당신이 사용하는 경우 등 일반적으로 bash
, zsh
, ksh
당신은 그런 것들에 대해 신경 안 - 무엇이든.
ksh
는 bash
'기능 세트가 대부분 기능의 하위 세트 이기 때문에 이것이 의미하는 바입니다 .
쉘이 Dash / Bash를 사용하고 있는지 확인하려면 다음을 수행하십시오.
ls –la /bin/sh
:
결과가 /bin/sh -> /bin/bash
==> 인 경우 쉘은 Bash를 사용하고 있습니다.
결과가 /bin/sh ->/bin/dash
==> 인 경우 쉘은 Dash를 사용하고 있습니다.
Bash에서 Dash로 또는 그 반대로 변경하려면 아래 코드를 사용하십시오.
ln -s /bin/bash /bin/sh
(쉘을 Bash로 변경)
참고 : 위의 명령으로 / bin / sh가 이미 존재한다는 오류가 발생하면 / bin / sh를 제거하고 다시 시도하십시오.
아래 명령을 사용하십시오.
ps -p $$ | tail -1 | awk '{print $4}'
echo $SHELL
당신이하려는 일을하고 잘합니다. $SHELL
환경 변수에는 현재 실행중인 쉘이 아닌 현재 사용자의 기본 쉘이 포함되어 있기 때문에 두 번째 것도 좋지 않습니다. 내가 예에 대한 경우 bash
기본 쉘로 설정, 실행 zsh
하고 echo $SHELL
, 그것을 인쇄 할 수 있습니다 bash
.
echo $SHELL
쓰레기 일 수 있습니다 : ~ $ echo $SHELL /bin/zsh ~ $ bash bash-4.3$ echo $SHELL /bin/zsh bash-4.3$
이것은 RHEL ( Red Hat Linux ), macOS, BSD 및 일부 AIX에서 잘 작동합니다 .
ps -T $$ | awk 'NR==2{print $NF}'
또는 pstree 를 사용할 수있는 경우 다음 중 하나가 작동해야 합니다.
pstree | egrep $$ | awk 'NR==2{print $NF}'
!
대체 기능을 수행 합니까?)는 셸 이름을 찾는 것보다 이식성이 뛰어납니다. 지역 관습은/bin/sh
실제로 애쉬, 대시, 배쉬 등의 이름을 가진 무언가를 실행하게 할 수도 있습니다 .