IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Android设备adb shell命令行提示符定制修改

    FranzKafka95发表于 2024-03-27 14:55:42
    love 0
    Read Time:2 Minute, 24 Second

    当我们通过adb shell进入Android的shell环境时,命令行左侧都会显示当前的设备名。如下所示:

    c1200:/ $

    在Linux环境下,当我们通过SSH连接进入Linux Shell时,命令行左侧同样会显示当前设备的名称,不同的时,Linux环境下显示的设备名称,其实是对应当前Linux设备的Hostname与User相结合。

    在Linux环境中,命令行提示符的显示由PS1环境变量决定,Android内同样如此,这里我们查看一下PS1环境变量:

    PS C:\Users\bst> adb shell
    c1200:/ # echo $PS1
    ${| local e=$? (( e )) && REPLY+="$e|" return $e }$USER@$HOSTNAME:${PWD:-?} #
    c1200:/ #

    该环境变量的值设定的含义具体解析如下:

    ${| … }:这是一种形式的命令替换,它执行其中的命令并将其输出作为字符串插入到PS1中。在这个情况下,整个 ${| … } 结构实际上是用来设置提示符的。

    local e=$?:这一行声明了一个局部变量 e 来存储上一个命令的退出状态,熟悉shell的朋友应该知道$? 是一个特殊变量,保存了上一个执行命令的退出状态码。

    (( e )) && REPLY+=”$e|”:这是一个条件表达式,它检查变量 e 的值是否为非零。如果是,它将上一个命令的退出状态码附加到提示符字符串 REPLY 中,以及一个竖线(|),表示非零退出状态码。

    return $e:这一行会返回上一个命令的退出状态码。这意味着,如果前一个命令失败(退出状态码非零),那么整个提示符将会包含该失败命令的退出状态码,并且Shell的退出状态码将会被设置为该值。

    $HOSTNAME:这是主机名变量,用于显示当前主机的名称。

    ${PWD:-?}:这是当前工作目录的变量。${PWD} 会显示当前工作目录的绝对路径。如果当前工作目录无法获取,它会显示一个问号(?)作为占位符。

    所以,综上所述,这个 PS1 设置的含义是:显示主机名、当前工作目录的绝对路径,并在提示符中显示上一个命令的退出状态码(如果存在),以及一个竖线分隔符;那么PS1是如何被设置的呢,关于这部分的设置逻辑,这里我们需要参考sh的源码:

    //external/mksh/src/main.c
    if (Flag(FLOGIN))
                include(substitute("$HOME/.profile", 0), 0, NULL, true);
    if (Flag(FTALKING)) {
           cp = substitute("${ENV:-" MKSHRC_PATH "}", DOTILDE);
           if (cp[0] != '\0')
              // include属于自定义函数
              include(cp, 0, NULL, true);
    }
    
    //
    include(const char *name, int argc, const char **argv, bool intr_ok)
    {
        Source *volatile s = NULL;
        struct shf *shf;
        const char **volatile old_argv;
        volatile int old_argc;
        int i;
    
        shf = shf_open(name, O_RDONLY | O_MAYEXEC, 0, SHF_MAPHI | SHF_CLEXEC);
        if (shf == NULL)
            return (-1);
    
        if (argv) {
            old_argv = e->loc->argv;
            old_argc = e->loc->argc;
        } else {
            old_argv = NULL;
            old_argc = 0;
        }
        newenv(E_INCL);
        if ((i = kshsetjmp(e->jbuf))) {
            quitenv(s ? s->u.shf : NULL);
            if (old_argv) {
                e->loc->argv = old_argv;
                e->loc->argc = old_argc;
            }
            switch (i) {
            case LRETURN:
            case LERROR:
            case LERREXT:
                /* see below */
                return (exstat & 0xFF);
            case LINTR:
                /*
                 * intr_ok is set if we are including .profile or $ENV.
                 * If user ^Cs out, we don't want to kill the shell...
                 */
                if (intr_ok && ((exstat & 0xFF) - 128) != SIGTERM)
                    return (1);
                /* FALLTHROUGH */
            case LEXIT:
            case LLEAVE:
            case LSHELL:
                unwind(i);
                /* NOTREACHED */
            default:
                internal_errorf(Tunexpected_type, Tunwind, Tsource, i);
                /* NOTREACHED */
            }
        }
        if (argv) {
            e->loc->argv = argv;
            e->loc->argc = argc;
        }
        s = pushs(SFILE, ATEMP);
        s->u.shf = shf;
        strdupx(s->file, name, ATEMP);
        i = shell(s, 1);
        quitenv(s->u.shf);
        if (old_argv) {
            e->loc->argv = old_argv;
            e->loc->argc = old_argc;
        }
        /* & 0xff to ensure value not -1 */
        return (i & 0xFF);
    }

    这里MKSHRC_PATH的值为/system/etc/mkshrc,其内容为:

    set +o nohup
    if (( USER_ID )); then PS1='$'; else PS1='#'; fi
    PS4='[$EPOCHREALTIME] '; PS1='${|
        local e=$?
        (( e )) && REPLY+="$e|"
        return $e
    }$HOSTNAME:${PWD:-?} '"$PS1 "

    所以这里PS1的设置逻辑其实是通过sh解析/system/etc/mkshrc文件后配置到环境变量内的。

    所以如果我们要修改命令行提示符,可以通过修改/system/etc/mkshrc文件的配置,比如我希望命令行提示符显示当前所属用户(一般情况下为shell用户,adb root之后则为root用户),则可以修改/system/etc/mkshrc为如下所示:

    set +o nohup
    if (( USER_ID )); then PS1='$'; else PS1='#'; fi
    PS4='[$EPOCHREALTIME] '; PS1='${|
        local e=$?
        (( e )) && REPLY+="$e|"
        return $e
    }$USER@$HOSTNAME:${PWD:-?} '"$PS1 "

    之后我们再重新adb shell进入,看看效果:

    shell@c1200:/ $

    如果我们先adb root,再adb shell进入,会发现命令行提示符为:

    root@c1200:/ $

    是不是不一样了?是不是很神奇!

    除此之后,我们应该还关注到在设置PS1的过程中用到HOSTNAME环境变量,该变量的值与一般是与ro.product.device的值保持一致的,而ro.product.device与Android编译配置时的环境变量TARGET_DEVICE保持一致,TARGET_DEVICE的值又与我们的编译配置PRODUCT_DEVICE配置一致;

    所以如果我们要修改命令行提示符中的设备标识,一来我们可以修改编译配置时的PRODUCT_DEVICE名称,二来可以修改/system/etc/mkshrc,设定HOSTNAME的值即可。

    Happy
    Happy
    0 0 %
    Sad
    Sad
    0 0 %
    Excited
    Excited
    0 0 %
    Sleepy
    Sleepy
    0 0 %
    Angry
    Angry
    0 0 %
    Surprise
    Surprise
    0 0 %

    The post Android设备adb shell命令行提示符定制修改 first appeared on FranzKafka Blog.



沪ICP备19023445号-2号
友情链接