代码之家  ›  专栏  ›  技术社区  ›  josh

如何确定我正在处理的shell?

  •  536
  • josh  · 技术社区  · 14 年前

    如何确定当前正在处理的shell?

    将输出的 ps 单凭命令就够了?

    如何在不同风格的Unix中实现这一点?

    23 回复  |  直到 7 年前
        1
  •  691
  •   codechurn    7 年前
    • 有3种方法可以找到 名称 当前shell的可执行文件:

      请注意,如果shell的可执行文件是 /bin/sh 但它真的被重新命名了 bash 例如(经常发生)。

      所以你的第二个问题是 ps 输出将做的回答为“ 并不总是 “。

      1. echo $0 -将打印程序名…在壳的情况下,它是实际的壳

      2. ps -ef | grep $$ | grep -v grep -这将在正在运行的进程列表中查找当前进程ID。由于当前进程是shell,因此将包括它。

        这不是100%可靠的,因为您可能有其他进程 聚苯乙烯 列表中包含与shell进程ID相同的数字,特别是如果该ID是一个小的(例如,如果shell的PID为“5”,则可以在同一个列表中找到名为“java5”或“perl5”的进程 grep 输出!). 这是“ps”方法的第二个问题,在无法依赖shell名称的基础上。

      3. echo $SHELL -当前外壳程序的路径存储为 SHELL 任何shell的变量。对于这个问题的警告是,如果您显式地将shell作为子进程(例如,它不是您的登录shell)启动,那么您将获得登录shell的值。如果有可能,请使用 聚苯乙烯 $0 方法。


    • 但是,如果可执行文件与实际shell不匹配(例如 /bin/SH 实际上是bash或ksh),您需要启发式方法。以下是特定于各种外壳的一些环境变量:

      • $version 设置在TCSH上

      • $BASH 被击垮

      • $shell (小写)在csh或tcsh中设置为实际shell名称

      • $ZSH_NAME 设置在ZSH上

      • KSH $PS3 $PS4 设置,而正常的Bourne外壳( sh 只有 $PS1 $PS2 集合。这似乎是最难区分的——在整个环境变量集合中 ksh 我们在Solaris上安装了Boxen是 $ERRNO , $FCEDIT , $LINENO , $PPID , PS3美元 , PS4美元 , $RANDOM , $SECONDS , $TMOUT .

        2
  •  83
  •   Matthew Slattery    14 年前

    ps -p $$

    应该在解决方案涉及的任何地方工作 ps -ef grep do(在任何支持 POSIX options for ps )并且不会受到对可能出现在其他地方的数字序列进行grepping所带来的误报的影响。

        3
  •  34
  •   Monolo    12 年前

    尝试

    ps -p $$ -oargs=
    

    ps -p $$ -ocomm=
    
        4
  •  22
  •   edwinksl    8 年前

    如果您只想确保用户使用bash调用脚本:

    if [ ! -n "$BASH" ] ;then echo Please run this script $0 with bash; exit 1; fi
    
        5
  •  20
  •   karlphillip    14 年前

    你可以试试:

    ps | grep `echo $$` | awk '{ print $4 }'
    

    或:

    echo $SHELL
    
        6
  •  11
  •   sr01853    12 年前

    $SHELL 不必总是显示当前外壳。它只反映要调用的默认shell。

    要测试以上内容,请说 bash 是默认外壳,请尝试 echo $SHELL 然后在同一个终端,进入另一个外壳(例如ksh)并尝试 贝壳 在这两种情况下,结果都是bash。

    要获取当前shell的名称,请使用 cat /proc/$$/cmdline 以及shell可执行文件的路径 readlink /proc/$$/exe

        7
  •  9
  •   ennuikiller    14 年前

    PS是最可靠的方法。shell envar不能保证被设置,即使是这样,它也很容易被欺骗。

        8
  •  8
  •   Abdel    9 年前

    我有一个简单的技巧来找到当前的外壳。只需键入一个随机字符串(它不是命令)。它将失败并返回“未找到”错误,但在行首,它将指出它是哪个shell:

    ksh: aaaaa: not found [No such file or directory]
    bash: aaaaa: command not found
    
        9
  •  7
  •   Six Uli Schlachter    8 年前

    这将始终提供实际使用的shell-获取实际可执行文件的名称,而不是shell名称(即 ksh93 而不是 ksh 等) /bin/sh 将显示实际使用的外壳:即 dash

    ls -l /proc/$$/exe | sed 's%.*/%%'
    

    我知道这里有很多人说 ls 输出应该被更新的处理,但是您使用的shell使用特殊字符命名或放在特殊字符命名目录中的可能性有多大?如果仍然是这样的话,这里还有很多其他的例子可以做不同的事情。

        10
  •  4
  •   David Ferenczy Rogožan Hugo L.M    10 年前

    我尝试过许多不同的方法,对我来说最好的方法是:

    ps -p $$

    它也适用于 赛文 并且不能产生假阳性作为pid grepping。通过一些清理,它只输出一个可执行文件名(在 赛文 有路径):

    ps -p $$ | tail -1 | awk '{print $NF}'
    

    您可以创建一个函数,这样就不必记住它:

    # print currently active shell
    shell () {
      ps -p $$ | tail -1 | awk '{print $NF}'
    }
    

    …然后执行 shell .

    在Debian和Cygwin下测试。

        11
  •  4
  •   Matthew Stier    9 年前

    我的变体打印父进程。

    ps -p $$ | awk '$1 == PP {print $4}' PP=$$
    

    为什么运行不必要的应用程序,而“awk”可以为您做到这一点?

        12
  •  3
  •   carlo    11 年前

    前提是你的 /bin/sh 支持POSIX标准,您的系统具有 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}'
    
        13
  •  2
  •   Moisei    14 年前
    echo $$ # Gives the Parent Process ID 
    ps -ef | grep $$ | awk '{print $8}' #use the PID to see what the process is.
    

    http://www.unix.com/unix-dummies-questions-answers/10390-how-do-you-know-what-your-current-shell.html

        14
  •  1
  •   zaga    14 年前

    在Mac OS X上(&freebsd):

    ps -p $$ -axco command | sed -n '$p' 
    
        15
  •  1
  •   Alex Dupuy Shayan    10 年前

    如果您只想检查是否正在运行(特定版本的)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版本是兼容的。

        16
  •  1
  •   ajaaskel    10 年前

    不需要从“ps”的输出中对pid进行grepping,因为您可以从/proc目录结构中读取任何pid的相应命令行:

    echo $(cat /proc/$$/cmdline)
    

    然而,这可能并不比简单地:

    echo $0
    

    关于运行实际不同于名称所指示的shell,一个想法是使用以前获得的名称从shell请求版本:

    <some_shell> --version
    

    sh似乎失败了,退出代码为2,而其他人给出了一些有用的东西(但我无法验证所有这些,因为我没有它们):

    $ sh --version
    sh: 0: Illegal option --
    echo $?
    2
    
        17
  •  1
  •   rominf Alex Martelli    10 年前

    所有答案都不适用 fish shell(它没有变量 $$ $0 )

    这对我有用 sh , bash , , ksh , csh , true , tcsh zsh ;打开SUSE 13.2):

    ps | tail -n 4 | sed -E '2,$d;s/.* (.*)/\1/'
    

    此命令输出字符串如下 猛击 . 我只在这里用 ps , tail sed (没有GNU扩展;尝试添加 --posix 检查一下。它们都是标准的POSIX命令。我肯定 可以移除,但我的 塞德 傅的力气不够。

    在我看来,这个解决方案不是非常可移植的,因为它在OS X上不起作用。(

        18
  •  1
  •   theoden8 Yomal    9 年前

    这不是很干净的解决方案,但可以满足您的需要。

    我知道答案在这个美好的2015年有点晚了,但是…

    #MUST BE SOURCED..
    getshell() {
        local shell="`ps -p $$ | tail -1 | awk '{print $4}'`"
    
        shells_array=(
        # It is important that the shells are listed by the decrease of their length name.
            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.

    不过,这种方法只适用于像ksh这样的外壳。

        19
  •  1
  •   wickles    7 年前

    我的解决方案:

    ps -o command | grep -v -e "\<ps\>" -e grep -e tail | tail -1
    

    这应该可以在不同的平台和外壳之间进行移植。它使用 ps 和其他解决方案一样,但它不依赖于 sed awk 过滤掉管道中的垃圾 聚苯乙烯 所以shell应该始终是最后一个条目。这样我们就不需要依赖于不可移植的PID变量,也不需要选择正确的行和列。

    我在Debian和MacOS上用bash、zsh和fish进行了测试(在不改变fish的表达式的情况下,大多数解决方案都不起作用,因为它使用了不同的PID变量)。

        20
  •  1
  •   Devang Paliwal    7 年前

    有很多方法可以找到shell及其对应的版本。这里有几个对我有用。

    直行

    1. $GT; 回声0美元 (给你程序名。在我的例子中,输出是 -巴什 )
    2. $GT; 贝壳 (这将带您进入shell,并在提示中获得shell名称和版本。以我为例 BASH3.2美元 )
    3. $GT; 回声壳牌 (这将为您提供可执行路径。以我为例 /BI/BASH )
    4. $GT; $shell—版本 (这将提供有关具有许可证类型的shell软件的完整信息)

    黑客方法

    $>*****(键入一组随机字符,在输出中您将获得外壳名称。以我为例 -bash:chapter2-a-sample-isomorphic-app:未找到命令 )

        21
  •  1
  •   Shiva    7 年前

    要知道shell是否使用了dash/bash,请执行以下操作。

    1) LS_瘻LA/BIN/SH , 如果结果是 /bin/sh->/bin/bash ==>那么您的shell正在使用bash。

    如果结果是 /bin/sh->/bin/破折号 ==>然后您的外壳使用破折号。

    如果您想从bash更改为dash或反之亦然,请使用下面的代码 ln-s/bin/bash/bin/sh/回车 (将shell改为bash)

    注意:如果上述命令导致错误,说明/bin/sh已经存在,请删除/bin/sh并重试。

        22
  •  0
  •   Ranjithkumar T    10 年前

    请使用以下命令:

     # ps -p $$ | tail -1 | awk '{print $4}'
    
        23
  •  -1
  •   martin zahrubsky    7 年前

    这个对瑞尔、MacOS、BSD和一些aixes很有效。

    ps -T $$ | awk 'NR==2{print $NF}' 
    

    或者,如果pstree可用,也可以使用下面的方法,

    pstree | egrep $$ | awk 'NR==2{print $NF}'