AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 535925
Accepted
sourcejedi
sourcejedi
Asked: 2019-08-17 10:37:35 +0800 CST2019-08-17 10:37:35 +0800 CST 2019-08-17 10:37:35 +0800 CST

如果我从“sudo --login”运行它,“sh -c”不会扩展位置参数。有没有解决的办法?

  • 772

我写了一个使用位置参数的“内联脚本”,例如

$ sudo sh -c 'echo "p0=$0" && echo "p1=$1" && echo "p2=$2" && echo "all=$@"' sh 1 2
p0=sh
p1=1
p2=2
all=1 2

我实际上想使用sudo --login. 但是位置参数不起作用。有没有办法让它们工作?

(如果行为在某处被记录或标准化,我也​​很感兴趣)。

$ sudo --login sh -c 'echo "p0=$0" && echo "p1=$1" && echo "p2=$2" && echo "all=$@"' sh 1 2
p0=-bash
p1=
p2=
all=1 2

软件版本:

$ sh --version
GNU bash, version 5.0.7(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

$ sudo --version
Sudo version 1.8.27
Sudoers policy plugin version 1.8.27
Sudoers file grammar version 46
Sudoers I/O plugin version 1.8.27
shell-script sudo
  • 1 1 个回答
  • 494 Views

1 个回答

  • Voted
  1. Best Answer
    Stéphane Chazelas
    2019-08-17T12:22:38+08:002019-08-17T12:22:38+08:00

    出于同样的原因

    sudo --login echo '$HOME'
    

    不输出$HOME,而是$HOME变量的内容(目标用户的,由 设置sudo)。

    在您的情况下,这不是因为sh -c 没有扩展位置参数,而是因为$0, $1,在启动$2时已经(通过登录外壳)扩展了sh。

    这里更令人惊讶的是为什么你会看到all=1 2. $@这与您看到的原因相同sudo --login echo '$@'。

    -s/--shell和-i/都--login运行一个 shell 来运行命令。但sudo它以一种非常奇怪的方式进行。

    我希望sudo -s 'some shell code'运行一个 shell 来解释some shell code,但这不是它的作用。使用-s,它仍然希望运行一个简单的命令,并尝试引用(使用\)一些字符,以期通过该 shell 实现它。

    你不是故意的sudo -s 'echo test',但是sudo -s echo test。在第一种情况下,sudo 实际上是echo\ test作为 shell 代码传递的。在类似 Bourne 的 shell 中,它会尝试运行一个名为'echo test'. 使用rcshell,它将运行一个echo\以test作为参数调用的命令。

    除了 SPC 之外,还有一些字符会sudo转义。这包括反引号, ;, |, (, ), *, &, =,\但奇怪的是,不是(或者这可能是这些/选项$中唯一存在的理由:让 shell 扩展变量)。-s--login

    它确实包括@。如果您查看代码,它会转义除 ASCII alnum、 和 之外的_所有-字节$。

     if (!isalnum((unsigned char)*src) && *src != '_' && *src != '-' && *src != '$')
       *dst++ = '\\';
    

    所以:

    sudo -s echo '$@'
    

    sudo实际运行"$SHELL" -c 'echo $\@',这解释了为什么在您的示例中,$@不是由启动的 shellsudo --login 而是由您告诉它运行的 shell 扩展的。

    在你的

    sudo sh -c 'echo "p0=$0" && echo "p1=$1" && echo "p2=$2" && echo "all=$@"' sh 1 2
    

    sudo运行root的登录外壳(bash在您的情况下)并告诉它解释:

    sh -c echo\ \"p0\=$0\"\ \&\&\ echo\ \"p1\=$1\"\ \&\&\ echo\ \"p2\=$2\"\ \&\&\ echo\ \"all\=$\@\" sh 1 2
    

    参数已用空格和所有 SPC、"、=、&、@字符连接,但没有$被转义。因为那些$没有被转义的 bash 登录 shell 会扩展$0, $1,$2但不是$\@因为那个反斜杠。

    你可以看到它:

    $ SHELL=echo sudo -s sh -c 'echo "p0=$0" && echo "p1=$1" && echo "p2=$2" && echo "all=$@"' sh 1 2
    -c sh -c echo\ \"p0\=$0\"\ \&\&\ echo\ \"p1\=$1\"\ \&\&\ echo\ \"p2\=$2\"\ \&\&\ echo\ \"all\=$\@\" sh 1 2
    

    所以登录bashshell最终sh以-c第一个参数运行,

    echo "p0=-bash" && echo "p1=" && echo "p2=" && echo "all=$@"
    

    作为第二个参数,sh, 1,2作为第 3、第 4 和第 5 个。

    要解决它,您可以使用${0}而不是$0, 因为sudo将其转换为$\{0\}可防止登录 shell 将其扩展到其内容 $0:

    $ sudo --login sh -c 'echo "p0=${0}" && echo "p1=${1}" && echo "p2=${2}" && echo "all=${@}"' sh 1 2
    p0=sh
    p1=1
    p2=2
    all=1 2
    

    编辑:历史揭示了其背后的原因

    查看代码时的更多发现。$显然是在 2013 年通过这种变化引入了non-escaping 。其中指的是bug#564指的是bug#413。

    看起来在那个 bug#413 被"fixed"之前,sudo表现得和我预期的一样。

    那是:

    sudo -i 'some shell code'
    

    让登录 shell 解释该 shell 代码(并sudo -s 'some shell code'解释$SHELL该 shell 代码)。但是 bug#413 解决方案破坏了它,因为报告错误的人不理解它是这样工作的。并且错误#564 进一步破坏了它(试图仅恢复错误#413 解决方案引入的部分破坏)。

    我从 2009 年开始编译sudo1.7.1 并且-s/-i选项按我预期的那样工作。1.7.3(具有 bug#413 分辨率)的工作方式与您显然预期的一样:

    $ sudo-1.7.1 -i 'echo "$SHELL"'
    /bin/bash
    $ sudo-1.7.3 -i 'echo "$SHELL"'
    -bash: echo "$SHELL": command not found
    $ sudo-1.8.21p2 -i 'echo "$SHELL"'
    -bash: echo "/bin/bash": No such file or directory
    
    $ sudo-1.7.3 -i sh -c 'echo "p0=$0" && echo "p1=$1" && echo "p2=$2" && echo "all=$@"' sh 1 2
    p0=sh
    p1=1
    p2=2
    all=1 2
    

    在修复该错误#413 时引入的转义很容易被愚弄,因为\在所有字节(而不是字符)前面敲击 a 并不适用于所有人。

    除了rcwhere\甚至不是引用运算符的明显情况之外,在大多数 shell 中,换行符不能用 引用\:

    $ SHELL=sh sudo -s echo $'a\nb'
    ab
    $ SHELL=csh  sudo -s echo $'a\nb'
    a b
    

    这也意味着空参数被丢弃:

    $ sudo printf '<%s>\n' a '' b
    <a>
    <>
    <b>
    $ sudo -s printf '<%s>\n' a '' b
    <a>
    <b>
    

    \此外,通过在每个byte之前插入 a ,它将字符转换为字符集中的其他字符,其中\在其他字符中找到字节 0x5c (的编码):

    $ SHELL=bash LC_ALL=zh_HK.big5hkscs sudo -s echo $'\xa3``uname`\xa3`'
    bash: line 2: Linuxα: command not found
    α
    

    0xa3 0x60 是该语言环境中的希腊 Epsilon。sudo 将 0x60s 更改为 0x5c 0x60 和 0xa3 0x5c 是希腊字母,这就解释了为什么uname运行命令。sudo改变了

    ε`uname`ε
    

    至

    \α`\`uname\`\α`
    

    当然,行为最终令人惊讶,因为$-, $$, 位置参数和$varname(其中varname是有效的 POSIX 变量名)被扩展,但其他参数(如$@这里,还有$!, $?, $*, $#)或${varname}or $var[1]( csh/ tcsh/ zsh) 或$var(1)( rc/ es/...)。

    • 9

相关问题

  • 以其他用户身份运行单个命令;sudo 的限制

  • 通过命令的标准输出以编程方式导出环境变量[重复]

  • 按分隔符拆分并连接字符串问题

  • MySQL Select with function IN () with bash array

  • 允许用户以 root 身份运行命令

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve