直接运行命令和使用`bash -c` 有什么区别?

Tim*_*Tim 11 bash

对于命令(内置或外部),直接在 bash shell 进程中运行它和bash -c在 bash shell中运行它有什么区别?与彼此相比,它们的优点和缺点是什么?

For example, in a bash shell, run `date` directly, and run `bash -c
date`. Also consider a builtin command instead of an external one.
Run Code Online (Sandbox Code Playgroud)

G-M*_*ca' 13

  1. -c选项允许程序运行命令。分叉和做要容易得多

    execl("/bin/sh", "sh", "-c", "date | od -cb  &&  ps > ps.out", NULL);
    
    Run Code Online (Sandbox Code Playgroud)

    比分叉,创建管道,再次分叉,调用execl每个孩子,调用wait,检查退出状态,再次分叉,调用close(1),打开文件,确保它在文件描述符上打开?1,然后再做一次execl。我相信这就是最初创建该选项的原因。

    system()库函数运行通过上述方法的指令。

  2. 它提供了一种接受任意复杂命令并使其看起来像一个简单命令的方法。这对于运行用户指定命令(例如find … -exec或 )的程序很有用xargs。但你已经知道了;这是您问题的答案的一部分, 如何将复合命令指定为另一个命令的参数?
  3. 如果您运行的是 bash 以外的交互式 shell,它会派上用场。相反,如果您正在运行 bash,则可以使用此语法

    $ ash -c "命令"
                 ?
     
    $ csh -c "命令"
                 ?
     
    $ dash -c "命令"
                 ?
     
    $ zsh -c "命令"
                 ?

    在另一个 shell 中运行一个命令,因为所有这些 shell 也识别该-c选项。当然,您可以使用

    $灰
    ash$命令
            ?
    ash$ 退出
     
    $ csh
    csh$命令
            ?
    csh$ 退出
     
    $破折号
    破折号$命令
            ?
    破折号$退出
     
    $ zsh
    zsh$命令
            ?
    zsh$ 退出

    我用ash$ , etc. 来说明来自不同 shell 的提示;你可能不会真正得到那些。

  4. 如果您想在“新鲜”的 bash shell 中运行一个命令,它会派上用场;例如,

    $ ash  -c "command"
                 ?
     
    $ csh  -c "command"
                 ?
     
    $ dash -c "command"
                 ?
     
    $ zsh  -c "command"
                 ?

    或者

    $ ash
    ash$ command
            ?
    ash$ exit
     
    $ csh
    csh$ command
            ?
    csh$ exit
     
    $ dash
    dash$ command
            ?
    dash$ exit
     
    $ zsh
    zsh$ command
            ?
    zsh$ exit
  5. 以上是一种误导性的过度简化。当 bash 与 一起运行时-c,它被认为是一个非交互式shell ~/.bashrc,除非-i指定,否则它不会读取。所以,

    $输入cp
    cp 别名为 'cp -i'           # 在~/.bashrc 中定义
     
    $ cp .file1 文件2
    cp:覆盖'file2'?n
     
    $ bash -c "cp .file1 file2"
                                      # 现有文件未经确认即被覆盖!
    $ bash -c -i "cp .file1 file2"
    cp:覆盖'file2'?n

    您可以使用-ci,-i -c-ic代替-c -i

    这可能在某种程度上适用于第 3 段中提到的其他 shell,因此长格式(即第二种格式,实际上与键入的数量完全相同)可能更安全,尤其是如果您设置了初始化/配置文件?为那些贝壳做准备。

  6. 正如通配符解释的那样,由于您正在运行一个新的进程树(一个新的 shell 进程,可能还有它的子进程),在子 shell 中对环境所做的更改 不会影响父 shell(当前目录、环境值)变量、函数定义等)因此,很难想象一个 shell 内置命令在由sh?-c.? fg, bg,jobs不能影响或访问由父 shell 启动的后台作业,也不能wait等待它们。  本质上等同于直接从交互式 shell 以正常方式运行。  浪费时间。  和sh?-c "exec some_program"some_programsh?-c exitulimitumask 可以更改子进程的系统设置,然后退出而不执行它们。

    几乎唯一可以在sh?-c上下文中起作用的内置命令是kill. 当然,只产生输出的命令(echoprintfpwdtype)不受影响,而且,如果你写一个文件,它会一直存在。

  7. 当然,您可以将内置 命令外部命令结合使用;例如,
    sh?-c "cd some_directory ; some_program "
    但是您可以使用普通子外壳实现基本相同的效果:
    (cd some_directory ; some_program )
    这是更有效的。可以说相同的(两个部分)类似的东西
    sh?-c "umask 77; some_program "
    ulimit(或shopt)。并且由于您可以将任意复杂的命令放在后面-c- 直到一个成熟的 shell 脚本的复杂性 - 您可能有机会使用任何内置命令;例如sourcereadexporttimessetunset等。


Wil*_*ard 7

运行bash -c "my command here"与仅运行my command here的主要区别在于,前者启动子shell,后者运行当前shell 中的命令。

至于内置命令与外部命令,它并没有真正相关——任何你可以在当前 shell 中运行的东西,你都可以在子 shell 中运行。

但是,效果存在许多差异:

  • 在子 shell 中对环境所做的更改不会影响父 shell(当前目录、环境变量的值、函数定义等)
  • 在父 shell 中设置的未导出的变量在子 shell 中将不可用。

这远不是一个详尽的差异列表,但它包含了关键点:您正在运行一个不同的进程bash -c;它与原始 shell 的过程不同。

生成子shell也会导致性能下降;如果您的脚本经常运行,或者您的命令在某种循环中,这将是最相关的。


rɑː*_*dʒɑ -1

-c 字符串

如果存在 -c 选项,则从字符串中读取命令。如果字符串后面有参数,它们将被分配给位置参数,从 $0 开始。

我想这会解决你的问题