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 / 问题 / 484362
Accepted
filbranden
filbranden
Asked: 2018-11-27 20:48:02 +0800 CST2018-11-27 20:48:02 +0800 CST 2018-11-27 20:48:02 +0800 CST

"sudo -s <command>" 在 shell 中运行命令,但通配符或元字符不起作用

  • 772

使用sudo -s(“--shell”选项的缩写)时,可以传递“sudo”命令,在这种情况下,它将在由“sudo”作为目标用户启动的 shell 中运行命令。

(同样,sudo -i也可作为“--login”选项使用,也可以启动一个 shell 并类似地接受一个命令,其行为方式相同。)

在许多情况下,通过 shell 在 sudo 中运行命令可能很重要:

  • 在当前用户无权访问但 root 可以访问的目录下使用通配符时,该命令需要在 root shell 下运行才能正确扩展通配符。
  • 运行整个管道,许多命令链接在管道 ( |) 中。
  • 在运行 shell 内置程序时,例如for,if等。在单个下运行一个小的整个内联“脚本”sudo可能很有用。

“-s”选项的文档说(强调我的):

运行由SHELL环境变量指定的 shell(如果已设置)或由调用用户的密码数据库条目指定的 shell。如果指定了命令,则通过 shell 的-c选项将其传递给 shell 以执行。如果未指定命令,则执行交互式 shell。请注意,与交互式会话相比,当指​​定命令时,大多数 shell 的行为都不同;有关详细信息,请参阅 shell 手册。

换句话说,当传递sudo -s命令时,它使用-c选项传递给shell,该选项接受一个带有“脚本”的字符串,然后继续将其作为shell脚本执行。

该文档实际上并没有进一步说明如何使用此选项或提供示例,只是说“请参阅 shell 手册以获取详细信息”。这意味着收到的命令直接传递给 shell 的-c选项。然而,事实证明,事实并非如此。

向它传递一个包含多个单词的 shell 脚本失败:

$ sudo -s 'ls -ld /var/empty'
/bin/bash: ls -ld /var/empty: No such file or directory

错误消息暗示它试图将整个字符串作为一个简单的命令运行......嗯,好的,所以也许添加空格会起作用?是的,情况就是这样:

$ sudo -s ls -ld /var/empty
drwxr-xr-x. 3 root root 18 Jul 12 21:48 /var/empty

不过,这并不是 shell 的真正-c工作方式……哦,好吧,让我们尝试使用一些元字符,例如~,它是主目录的快捷方式,来看看它的行为方式。注意~需要引用,以防止非 sudo shell 扩展它(在这种情况下,它将扩展到非 root 用户的家,而不是/root预期的):

$ sudo -s ls '~'
ls: cannot access '~': No such file or directory

好的,所以这不起作用,错误输出似乎暗示扩展没有发生,因为它在~那里保留了一个文字。

通配符呢?也不工作:

$ sudo -s ls '/root/*.cfg'
ls: cannot access '/root/*.cfg': No such file or directory

在这两种情况下,运行命令都可以$SHELL -c正常工作。在这种情况下,$SHELL是 bash,所以:

$ sudo bash -c 'ls ~'
anaconda-ks.cfg
$ sudo bash -c 'ls /root/*.cfg'
/root/anaconda-ks.cfg

一个例外是变量似乎对 起作用sudo -s,例如:

$ sudo -s echo '$HOME'
/root

所以:

  • 这里发生了什么?
  • 为什么通配符和元字符(例如)在传递给or~的命令上不起作用?sudo -ssudo -i
  • Given$SHELL -c需要一个带有脚本的字符串,但sudo -s需要多个参数,脚本是如何从参数中组装起来的?
  • 在 shell 上运行命令的可靠方法是什么sudo?
shell sudo
  • 1 1 个回答
  • 1119 Views

1 个回答

  • Voted
  1. Best Answer
    filbranden
    2018-11-27T20:48:02+08:002018-11-27T20:48:02+08:00

    TL;DR:在“--shell”或“--login”选项上执行命令时,sudo将转义大多数字符(使用反斜杠转义),包括所有元字符(除了$),还包括空格。

    这打破了您想要使用 shell 的每个用例,这使得sudo -s大多数情况下不适合运行需要作为 shell 命令运行的 shell 命令。

    代替sudo -s, 使用sudo sh -c '...'or sudo bash -c '...'(或任何预期$SHELL的东西。)代替sudo -i, 使用sudo bash -l -c '...'代替(假设 root 的 shell 再次是 bash 。)


    查看sudo 源代码的相关部分,有这个片段:

    /* quote potential meta characters */
    if (!isalnum((unsigned char)*src) && *src != '_' && *src != '-' && *src != '$')
        *dst++ = '\\';
    *dst++ = *src;
    

    该片段运行在每个参数的每个字符上。如果字符不是字母数字、下划线、破折号或美元符号,它将使用反斜杠进行转义。

    这意味着通配符*, ?,[...]等将转义为\*, \?, \[...\]。

    诸如~, ;,|等元字符也将转义为\~, \;, \|。

    带有空格的字符串ls /root将转义为ls\ /root.

    出于某种原因,$转义是一个例外,这就是为什么sudo -s echo '$HOME'有效,因为$将保持未转义。(请注意,这仅适用于变量,甚至不适用于${HOME}形式,在这种情况下,花括号将被转义,这将破坏表达式。)


    这种引用的后果是,大多数需要以 root 身份运行 shell 的情况并不能真正从以下sudo -s <command>格式中受益:

    • 不会扩展通配符,因为它们会被转义并且不能用作通配符。
    • 管道将不起作用,因为管道|将被转义并且也不起作用。
    • 像for并且if通常需要使用;的命令将被转义并且也不起作用。换行符将是另一种选择,但似乎也没有办法引入未转义的换行符。

    简而言之,这种形式sudo -s <command>似乎只适用于不涉及通配符、管道、scriptlet 等的情况。但是,您通常并不需要 shell 来运行这些命令!sudo <command>对于这些情况,仅在没有的情况下运行-s通常就足够了。

    目前尚不清楚 sudo 实施的动机是什么。也许是为了在添加或删除-s. 也许也是因为-i之前-s,在这种情况下,环境变量的设置方式存在一些细微差别......


    变通方法:变通方法是-c显式运行 shell。

    这涉及了解$SHELL目标用户的内容(可能与当前用户不匹配,因此$SHELL直接使用并不总是正确的。)

    例如,代替sudo -s ls -l '/root/*.cfg',使用:

    $ sudo bash -c 'ls -l /root/*.cfg'
    

    而不是sudo -i ls -l '~', 使用:

    $ sudo bash -l -c 'ls -l ~'
    

    (bash 的-l参数创建了一个“登录”shell,它等同于由 . 创建的那个sudo -i。)

    • 9

相关问题

  • 有没有办法让 ls 只显示某些目录的隐藏文件?

  • grep -v grep 有什么作用

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

  • 如何将带有〜的路径保存到变量中?

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

Sidebar

Stats

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

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

    • 4 个回答
  • Marko Smith

    ssh 无法协商:“找不到匹配的密码”,正在拒绝 cbc

    • 4 个回答
  • Marko Smith

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

    • 5 个回答
  • Marko Smith

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

    • 3 个回答
  • Marko Smith

    如何卸载内核模块“nvidia-drm”?

    • 13 个回答
  • 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
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Wong Jia Hau ssh-add 返回:“连接代理时出错:没有这样的文件或目录” 2018-08-24 23:28:13 +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
  • Martin Hope
    Bagas Sanjaya 为什么 Linux 使用 LF 作为换行符? 2017-12-20 05:48:21 +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