如何使用一行命令在“bash -c”中定义和使用“alias”?

如何使用一行命令在“bash -c”中定义和使用“alias”?

我正在尝试使用一行命令来定义和alias使用。bash -c

命令:

bash -c "eval $'df'"

工作正常,但是:

bash -c "eval $'alias df5=df\ndf5 -h'"

没有。为什么以及如何通过一行命令定义和使用alias内部?bash -c


善行难陀回答如何将eval包含新行的命令写入一行?

“The$'...'是一个“C 字符串”,在将其传递给 之前bash会将其中的 扩展\n为文字换行符eval

因此我的理解是必须'eval.此外,由于bash手册说:

将字符括在单引号 ( ') 中可保留引号内每个字符的字面值。单引号之间不能出现单引号,即使前面有反斜杠也是如此。

我的理解是,应该"在 the 之外使用,因为里面eval有.'eval


评论:

  • 如何将eval包含新行的命令写入一行?解释使用\n代替;
  • 这个问题背后的动机是,在我实际的整个命令中,我将别名命令用于其他事情(该命令看起来像docker run -it ubuntu:18.04 bash -c "eval $'alias pip=pip3\nsource blah.sh; exec bash")。哪里blah.sh 使用pip.完整的实际命令是:docker run --interactive --tty ubuntu:18.04 bash -c "apt update; apt install -y git nano wget htop python3 python3-pip unzip; git clone https://github.com/KhalilMrini/LAL-Parser; cd LAL-Parser/; alias pip=pip3; source requirements.sh; apt-get install -y libhdf5-serial-dev; alias python=python3 ; source parse.sh; exec bash",但我需要eval添加alias.该命令启动 Docker 容器,安装一些要求并运行一些 Python 代码。
  • 该命令面向非技术同事:我希望他们只运行一行命令,以便他们易于使用。因此,我不希望命令需要一个文件(例如,Dockerfile或脚本)来工作。bash
  • 以下命令:

    bash -c "
        eval 'alias df5=df
        df5 -h'
    "
    

    以及命令

    bash -c "
        alias df5=df
        df5 -h
    "
    

    也不行。错误bash: line 2: df5: command not found。结果似乎问题是aliasbash -c.我不知道为什么,想知道是否有一些解决方法。

答案1

编辑后的问题:

对于编辑后的问题,现在“在 exec bash 之后不需要交互式别名”:

是的,bash -c 失败:

$ bash -c "
       alias df5=df
       df5 -h
  "
bash: line 2: df5: command not found

但不是因为别名设置失败:

$ bash -c "
       alias df5=df
       alias df5
  "
alias df5=df

但是因为在非交互式 shell(主要是脚本)中,默认情况下不会扩展别名,因此您需要执行以下操作:

bash -c "
       alias df5=df
       shopt -s expand_aliases
       df5 -h
  "

这是使用函数而不是别名的重要原因之一。

如果这就是您需要克服的全部,那么使用:

docker run --interactive --tty ubuntu:18.04 \
    bash -c "
        shopt -s expand_aliases;
        apt update; 
        apt install -y git nano wget htop python3 python3-pip unzip;
        git clone https://github.com/KhalilMrini/LAL-Parser;
        cd LAL-Parser/; 
        alias pip=pip3; 
        source requirements.sh; 
        apt-get install -y libhdf5-serial-dev; 
        alias python=python3;
        source parse.sh;
        exec bash
    "

它应该作为单行代码(删除换行符)。如果没有请评论。


编辑前的问题:

之前的答案解决了以下问题:在 docker 启动的交互式 shell 中,如果末尾有exec bash.

阻止在新的交互式 shell 中使用别名的实际问题是整个命令:

docker run --interactive --tty ubuntu:18.04 \
    bash -c "
        apt update; 
        apt install -y git nano wget htop python3 python3-pip unzip;
        git clone https://github.com/KhalilMrini/LAL-Parser;
        cd LAL-Parser/; 
        alias pip=pip3; 
        source requirements.sh; 
        apt-get install -y libhdf5-serial-dev; 
        alias python=python3;
        source parse.sh;
        exec bash
    "

结束于exec bash.这将启动一个新的、干净的 bash 实例,没有别名,也没有执行脚本中的函数。

一种可能的解决方案是将 exec bash 替换为:

bash --rcfile <(echo '. ~/.bashrc; alias pip=pip3; alias python=python3')

这将使用户(运行 docker 命令的人)处于定义了两个别名的交互式 shell 中。

注意:这个想法尚未经过测试,因为它意味着安装了很多软件包,但应该可以工作。

至少,它指向真实的你的命令有问题。

答案2

使用 时bash,不扩展别名的原因是bash(与其他 shell 不同)不在交互模式下时不扩展别名。

除了这个 bash 特定的偏差之外,对于别名扩展还有更多重要的影响。 POSIX 标准的下一版本将包含相关描述,解释当别名未被授予工作权限时的痛苦。

别名在解析器的词法分析器部分内展开,并且只有在 shell 已知别名并且使用相关文本片段调用词法分析器时才会展开别名shell 已经意识到该别名。

因此,为了更好地理解别名扩展,了解 shell 是如何进行解析的也很重要。

shell 通常会解析整行输入,然后解释结果(这是识别别名命令时的情况)并继续解析下一行。

这解释了为什么在最好的情况下,别名会首先在下一行代码中展开。

Bourne Shell对于像和 这样的传统 shell ksh,这在某些情况下仍然不起作用。原因是传统的 shell 在开始解释结果之前,不是逐行而是逐块地解析一些输入。以下结构作为整体进行块式解析:

  • 来自 的整个 cmd-arg shell -c "cmd-arg",无论其大小如何

  • eval命令参数

  • 命令替换

  • shell 启动时执行的点脚本

  • .通过buitlin 命令执行的脚本

如果在这种情况下命令在子 shell 中运行,则定义的别名永远不会生效。在其他情况下,别名在执行已解析块并解析下一个输入后生效。

想要验证这一点的人可能喜欢检查NLFLGBourne Shell 或 ksh 源。如果此标志用于解析器,则处理换行符的方式与;看到 a 的方式相同。

正如您所看到的,在脚本中不使用别名会引起强烈的反响,即使当前使用的 shell 可以按预期方式工作,其他 shell 也不会表现出相同的行为。

相关内容