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

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

bash -c对于命令(内置或外部),直接在 bash shell 进程中运行与在 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.

答案1

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

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

    与 fork 相比,创建一个管道,再次 fork,调用execl每个子管道,调用wait,检查退出状态,再次 fork,调用close(1),打开文件,确保它在文件描述符 1 上打开,然后执行另一个execl。我相信这就是创建该选项的首要原因。

    system()函数按照上述方法运行命令。

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

    $灰-c“命令
     
    $ csh -c "命令
     
    $破折号-c“命令
     
    $ zsh -c "命令

    在另一个 shell 中运行一个命令,因为所有这些 shell 也都能识别该-c选项。当然你可以用以下方法获得相同的结果

    $ 灰分
    灰烬$命令
    灰$退出
     
    $csh
    csh$命令
    csh$ 退出
     
    $破折号
    破折号$命令
    破折号$退出
     
    $ 兹什
    zsh$命令
    zsh$ 退出

    我用ash$ 等来说明不同 shell 的提示;你可能实际上不会得到这些。

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

    $ ls -lA
    total 0
    -rw-r--r-- 1 gman gman   0 Apr 14 20:16 .file1
    -rw-r--r-- 1 gman gman   0 Apr 14 20:16 file2
    
    $ echo *
    file2
    
    $ shopt -s dotglob
    
    $ echo *
    .file1 file2
    
    $ bash -c "echo *"
    file2
    

    或者

    $ type shift
    shift is a shell builtin
    
    $ alias shift=date
    
    $ type shift
    shift is aliased to ‘date’
    
    $ bash -c "type shift"
    shift is a shell builtin
    
  5. 以上是一种误导性的过度简化。当 bash 运行时-c,它被认为是非交互式shell,并且它不读取~/.bashrc,除非-i指定。所以,

    $ 类型 cp
    cp 的别名为“cp -i”          # 定义于~/.bashrc
     
    $ cp .file1 文件2
    cp:覆盖“文件2”? n
     
    $ bash -c "cp .file1 file2"
                                      # 现有文件未经确认就被覆盖!
    $ bash -c -i "cp .file1 file2"
    cp:覆盖“文件2”? n

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

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

  6. 作为通配符解释,由于您正在运行一个新的进程树(一个新的 shell 进程及其可能的子进程),因此在子 shell 中对环境进行了更改 不能影响父 shell(当前目录、环境变量值、函数定义等)。因此,很难想象 shell 内置命令在sh -c.  fgbg、 和jobs不能影响或访问由父 shell 启动的后台作业,也不能wait等待它们。  本质上相当于只是运行sh -c "exec some_program"some_program正常方式,直接从交互式 shell。  sh -c exit是一个很大的浪费时间。  ulimit并且umask可以更改子进程的系统设置,然后退出而不执行它们。

    几乎唯一在上下文中起作用的内置命令sh -ckill.当然,仅产生输出的命令(echoprintfpwdtype不受影响,并且,如果您写入文件,该情况将持续存在。

  7. 当然你可以使用内置的和这个结合 外部命令;例如,
    sh -c "cd某个目录;某个程序
    但您可以使用普通的子 shell 实现基本相同的效果:
    (光盘某个目录;某个程序
    哪个更有效率。对于类似的事情可以说相同的(两个部分)
    sh -c“umask 77;某个程序
    ulimit(或shopt)。由于您可以在后面放置任意复杂的命令-c(最高可达完整 shell 脚本的复杂性),因此您可能有机会使用任何内置命令;例如,sourcereadexporttimessetunset等。

答案2

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

就内置命令与外部命令而言,它并没有真正的关系——任何事物您可以在当前 shell 中运行,也可以在子 shell 中运行。

然而,效果存在许多差异:

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

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

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

答案3

-c 选项基本上运行作为 CLI 参数而不是文件提供的迷你 shell 脚本。

$ bash -c the_script the_scriptname 1 2 3 

实际上相当于:

$ echo the_script > the_scriptname
$ bash the_scriptname 1 2 3
$ rm the_scriptname

正如你可以看到:

$ bash -c 'printf " ->%s\n" $0 "$@"; echo $-;' scriptname 1 2 3
   ->scriptname
   ->1
   ->2
   ->3
  hBc

(英语:$0 == scriptname; $@ == (1 2 3); bash 将: H灰烬命令;履行种族扩展,并且已经带着-c旗帜运行了)

和:

 $ echo 'printf " ->%s\n" $0 "$@"; echo $-;' > scriptname
 $ bash scriptname 1 2 3 
 ->scriptname
 ->1
 ->2
 ->3
 hB

答案4

-c 字符串

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

我想这会解决你的问题

相关内容