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
    • 最新
    • 标签
主页 / computer / 问题 / 1526229
Accepted
Kamil Maciorowski
Kamil Maciorowski
Asked: 2020-02-18 14:32:14 +0800 CST2020-02-18 14:32:14 +0800 CST 2020-02-18 14:32:14 +0800 CST

`sh -c 'some shell code' sh` 中的第二个 sh 是什么?

  • 772

问题

我遇到了以下代码段:

sh -c 'some shell code' sh …

(其中…表示零个或多个附加参数)。

我知道第一个sh是命令。我知道sh -c应该执行提供的 shell 代码(即some shell code)。第二个目的是什么sh?


免责声明

类似或相关的问题有时会在答案中正确使用后作为后续问题出现,sh -c提问者(或其他用户)想详细了解答案的工作原理。或者它可能是“这段代码做什么?”类型的更大问题的一部分。当前问题的目的是在下面提供一个规范的答案。

此处涵盖的主要问题、类似或相关问题是:

  1. 中的第二个sh是sh -c 'some shell code' sh …什么?
  2. 中的第二个bash是bash -c 'some shell code' bash …什么?
  3. find-sh里面有什么find . -exec sh -c 'some shell code' find-sh {} \;?
  4. 如果some shell code在一个 shell 脚本中并且我们调用./myscript foo …, thenfoo将被称为$1在脚本中。但是sh -c 'some shell code' foo …(或bash -c …)指的foo是$0。为什么会出现差异?
  5. 使用sh -c 'some shell code' foo …where foois a "random" 参数有什么问题?尤其是:

    • sh -c 'some shell code' "$variable"
    • sh -c 'some shell code' "$@"
    • find . -exec sh -c 'some shell code' {} \;
    • find . -exec sh -c 'some shell code' {} +

    我的意思是我可以使用$0代替$1inside some shell code,它不会打扰我。会发生什么坏事?

以上某些问题可能被认为是现有问题(例如这个问题)的重复(可能是跨站点重复)。我仍然没有找到旨在向想要理解的初学者解释问题的问题/答案,sh -c …以及在高质量答案中观察到的据称无用的额外论点。这个问题填补了空白。

shell-script sh
  • 1 1 个回答
  • 1020 Views

1 个回答

  • Voted
  1. Best Answer
    Kamil Maciorowski
    2020-02-18T14:32:14+08:002020-02-18T14:32:14+08:00

    初步说明

    sh -c 'some shell code'直接从 shell 调用的情况很少见。实际上,如果您在一个 shell 中,那么您可能会选择使用相同的 shell(或其子 shell)来执行some shell code. 从另一个sh -c工具(如find -exec.

    然而,这个答案的大部分都详细说明sh -c为一个独立的命令(它是),因为主要问题完全取决于sh. 稍后会在一些find看起来有用和/或有教育意义的地方使用一些示例和提示。


    基本答案

    中的第二个sh是sh -c 'some shell code' sh …什么?

    这是一个任意字符串。其目的是提供一个有意义的名称以在警告和错误消息中使用。在这里,sh但它可能是foo,shell1或special purpose shell(正确引用以包含空格)。

    Bash 和其他符合 POSIX 标准的 shell 在-c. 虽然我发现POSIX 文档过于正式,无法在此处引用,但摘录man 1 bash如下:

    bash [options] [command_string | file]
    

    -c
    如果-c存在该选项,则从第一个非选项参数中读取命令command_string。如果在 之后有参数 command_string,则将第一个参数分配给位置参数,$0并将任何剩余的参数分配给位置参数。赋值$0设置 shell 的名称,用于警告和错误消息。

    在我们的例子some shell code中command_string,第二个sh是“之后的第一个参数”。它被分配到$0的上下文中some shell code。

    这样的错误sh -c 'nonexistent-command' "special purpose shell"是:

    special purpose shell: nonexistent-command: command not found
    

    并且您立即知道它来自哪个外壳。sh -c如果您有很多调用,这很有用。" " 之后的第一个参数command_string可能根本不提供;在这种情况下sh(字符串)将被分配给$0如果外壳是sh,bash如果外壳是bash。因此这些是等价的:

    sh -c 'some shell code' sh
    sh -c 'some shell code'
    

    但是,如果您需要在之后传递至少一个参数some shell code(即可能应该分配给的参数$1,$2...),那么就没有办法省略将分配给的参数$0。


    差异?

    如果some shell code在一个 shell 脚本中并且我们调用./myscript foo …, thenfoo将被称为$1在脚本中。但是sh -c 'some shell code' foo …(或bash -c …)指的foo是$0。为什么会出现差异?

    通常,解释脚本的 shell 将脚本的名称(例如./myscript)作为参数数组中的第 0 个条目,稍后可用作$0. 然后该名称将用于警告和错误消息。通常这种行为是完全可以的,不需要$0手动提供。另一方面,sh -c没有脚本可以从中获取名称。仍然一些有意义的名称是有用的,因此提供它的方式。

    some shell code如果您停止将第一个参数视为代码的(某种)位置参数,差异将消失。如果some shell code在名为的脚本中myscript并且您调用./myscript foo …,则等效代码sh -c将是:

    sh -c 'some shell code' ./myscript foo …
    

    这里./myscript只是一个字符串,它看起来像一个路径,但这个路径可能不存在;字符串可能一开始就不同。这样就可以使用相同的 shell 代码。在这两种情况下,shell 都会分配foo给$1。没有差异。


    像对待$0一样的陷阱$1

    使用sh -c 'some shell code' foo …where foo 是“随机”参数有什么问题?[...] 我的意思是我可以使用$0代替$1inside some shell code,它不会打扰我。会发生什么坏事?

    在许多情况下,这将起作用。虽然有反对这种方法的论据。

    1. 最明显的缺陷是您可能会从调用的 shell 中收到误导性警告或错误。请记住,它们将从$0shell 上下文中扩展的任何内容开始。考虑这个片段:

      sh -c 'eecho "$0"' foo    # typo intended
      

      错误是:

      foo: eecho: command not found
      

      您可能想知道是否foo被视为命令。如果foo是硬编码且唯一的,那还不错;至少你知道这个错误与foo. 情况可能更糟:

      # as regular user
      sh -c 'ls "$0" > "$1"/' "$HOME" "/root/foo"
      

      输出:

      /home/kamil: /root/foo: Permission denied
      

      第一反应是:我的主目录怎么了?另一个例子:

      find /etc/fs* -exec sh -c '<<EOF' {} \;    # insane shell code intended
      

      可能的输出:

      /etc/fstab: warning: here-document at line 0 delimited by end-of-file (wanted `EOF')
      

      很容易认为有问题/etc/fstab; 或者想知道为什么代码要将其解释为 here-document。

      现在运行这些命令,看看当我们提供有意义的名称时错误有多准确:

      sh -c 'eecho "$1"' "shell with echo" foo    # typo intended
      sh -c 'ls "$1" > "$2"/' my-special-shell "$HOME" "/root/foo"
      find /etc/fs* -exec sh -c '<<EOF' find-sh {} \;    # insane shell code intended
      
    2. some shell code与脚本中的内容不同。这与上面阐述的所谓差异直接相关。这可能根本不是问题;仍然处于某种程度的shell-fu,您可能会欣赏一致性。

    3. 同样,在某种程度上,您可能会发现自己喜欢以正确的方式编写脚本。然后,即使您可以侥幸使用 using $0,您也不会这样做,因为这不是事情应该如何工作的方式。

    4. 如果要传递多个参数,或者如果事先不知道参数的数量并且需要按顺序处理它们,那么使用$0其中一个参数是个坏主意。$0设计上不同于$1or $2。some shell code如果使用以下一项或多项,这一事实将表现出来:

      • $#– 位置参数的数量不$0考虑,因为$0不是位置参数。

      • $@或$*-"$@"就像"$1", "$2", …,这​​个序列中没有"$0"。

      • for f do(等价于for f in "$@"; do)——$0从不分配给$f。

      • shift(shift [n]通常)——位置参数被移动,$0保持不变。

      特别考虑这种情况:

      1. 你从这样的代码开始:

        find . -exec sh -c 'some shell code referring "$1"' find-sh {} \;
        
      2. 您注意到它sh每个文件运行一个。这是次优的。

      3. 您知道-exec … \;替换{}为一个文件名,但可能-exec … {} +替换{}为多个文件名。您利用后者并引入一个循环:

        find . -exec sh -c '
           for f do
              some shell code referring "$f"
           done
        ' find-sh {} +
        

      这样的优化是一件好事。但如果你从这个开始:

      # not exactly right but you will get away with this
      find . -exec sh -c 'some shell code referring "$0"' {} \;
      

      并将其变成这样:

      # flawed
      find . -exec sh -c '
         for f do
            some shell code referring "$f"
         done
      ' {} +
      

      那么你将引入一个错误:来自扩展的第一个文件{}不会被some shell code referring "$f". Note使用尽可能多的参数-exec sh -c … {} +运行sh,但是对此有限制,如果有很多很多文件,那么一个sh是不够的,另一个sh进程将由find(可能还有另一个,另一个,......)产生。对于每个sh,您将跳过(即不处理)一个文件。

      要在实践中对此进行测试,请将字符串替换为some shell code referring并echo在包含少量文件的目录中运行生成的代码片段。最后一个片段不会打印.。

      所有这些并不意味着您根本不应该使用$0in some shell code。您可以并且应该将$0其用于其设计用途。例如,如果您想some shell code打印(自定义)警告或错误,则让消息以$0. 在后面提供一个有意义的名称some shell code并享受有意义的错误(如果有的话),而不是模糊或误导性的错误。


    最后提示:

    • find … -exec sh -c … 永远不会嵌入{}到shell 代码中。

    • 出于同样的原因some shell code,不应包含由当前 shell 扩展的片段,除非您真的知道扩展的值肯定是安全的。最佳做法是单引号引用整个代码(如上面的示例中,它总是'some shell code')并将每个非固定值作为单独的参数传递。这样的参数可以从内壳内的位置参数中安全地检索。导出变量也是安全的。运行它并分析每个的sh -c …输出(期望的输出是foo';date'):

      variable="foo';date'"
      
      # wrong
      sh -c "echo '$variable'" my-sh
      
      # right
      sh -c 'echo "$1"' my-sh "$variable"
      
      # also right
      export variable
      sh -c 'echo "$variable"' my-sh
      
    • 如果您sh -c 'some shell code' …在 shell 中运行,shell 将删除包含 ; 的单引号some shell code。然后内壳(sh)将解析some shell code。在这种情况下,正确引用也很重要。您可能会发现这很有用:参数扩展和引号内的引号。

    • 11

相关问题

  • 如何缩短 bash 中的变量名列表?

  • 发生某些输出后如何终止管道

  • 临时禁用 macOs 中的文件

  • 如何从 shell 脚本将插座电源切换到 Eaton ePDU G3

  • 文件描述符打开一次但关闭多次;为什么差异?

Sidebar

Stats

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

    如何减少“vmmem”进程的消耗?

    • 11 个回答
  • Marko Smith

    从 Microsoft Stream 下载视频

    • 4 个回答
  • Marko Smith

    Google Chrome DevTools 无法解析 SourceMap:chrome-extension

    • 6 个回答
  • Marko Smith

    Windows 照片查看器因为内存不足而无法运行?

    • 5 个回答
  • Marko Smith

    支持结束后如何激活 WindowsXP?

    • 6 个回答
  • Marko Smith

    远程桌面间歇性冻结

    • 7 个回答
  • Marko Smith

    子网掩码 /32 是什么意思?

    • 6 个回答
  • Marko Smith

    鼠标指针在 Windows 中按下的箭头键上移动?

    • 1 个回答
  • Marko Smith

    VirtualBox 无法以 VERR_NEM_VM_CREATE_FAILED 启动

    • 8 个回答
  • Marko Smith

    应用程序不会出现在 MacBook 的摄像头和麦克风隐私设置中

    • 5 个回答
  • Martin Hope
    CiaranWelsh 如何减少“vmmem”进程的消耗? 2020-06-10 02:06:58 +0800 CST
  • Martin Hope
    Jim Windows 10 搜索未加载,显示空白窗口 2020-02-06 03:28:26 +0800 CST
  • Martin Hope
    v15 为什么通过电缆(同轴电缆)的千兆位/秒 Internet 连接不能像光纤一样提供对称速度? 2020-01-25 08:53:31 +0800 CST
  • Martin Hope
    fixer1234 “HTTPS Everywhere”仍然相关吗? 2019-10-27 18:06:25 +0800 CST
  • Martin Hope
    andre_ss6 远程桌面间歇性冻结 2019-09-11 12:56:40 +0800 CST
  • Martin Hope
    Riley Carney 为什么在 URL 后面加一个点会删除登录信息? 2019-08-06 10:59:24 +0800 CST
  • Martin Hope
    zdimension 鼠标指针在 Windows 中按下的箭头键上移动? 2019-08-04 06:39:57 +0800 CST
  • Martin Hope
    jonsca 我所有的 Firefox 附加组件突然被禁用了,我该如何重新启用它们? 2019-05-04 17:58:52 +0800 CST
  • Martin Hope
    MCK 是否可以使用文本创建二维码? 2019-04-02 06:32:14 +0800 CST
  • Martin Hope
    SoniEx2 更改 git init 默认分支名称 2019-04-01 06:16:56 +0800 CST

热门标签

windows-10 linux windows microsoft-excel networking ubuntu worksheet-function bash command-line hard-drive

Explore

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

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve