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
    • 最新
    • 标签
主页 / ubuntu / 问题 / 1182642
Accepted
AlainD
AlainD
Asked: 2019-10-22 04:16:31 +0800 CST2019-10-22 04:16:31 +0800 CST 2019-10-22 04:16:31 +0800 CST

为什么在 Bash 脚本中将命令组合在一行中?

  • 772

我是 Linux 和 Bash 脚本的新手。在工作中,我见过具有类似结构的 Bash 脚本:

mkdir build && cd build && touch blank.txt

或者:

mkdir build; cd build; touch blank.txt

甚至是异国情调:

COMMAND="mkdir build && cd build && touch blank.txt"
eval ${COMMAND}

最后一个示例给出了一个可能的用例,其中单行可能有用,但通常以下内容更易于阅读并且(至少对我而言)允许您直观地调试脚本:

mkdir build
cd build
touch blank.txt

把所有东西都塞在一条线上有技术优势吗?

scripts command-line bash
  • 8 8 个回答
  • 22130 Views

8 个回答

  • Voted
  1. Best Answer
    pa4080
    2019-10-22T04:43:15+08:002019-10-22T04:43:15+08:00
    mkdir build && cd build && touch blank.txt
    

    在 Bash(以及其他一些 shell 和大多数高级编程语言)&&中是一个逻辑and,这意味着 - 如果上一个命令返回 true,则将执行下一个命令。还有逻辑或 ||。例如,您可以将这两个选项组合在一个语句中:

    mkdir /tmp/abc/123 && echo 'the dir is created' || echo "the dir isn't created"
    

    注意,构造cmd_1 && cmd_2 || comd_3不是if.. then.. else语句的替代,因为无论前面的哪个命令返回false,cmd_3都会执行。因此,您必须小心使用它的环境。这是一个例子:

    $ true && false || echo success
    success
    $ false && true || echo success
    success
    $ false && false || echo success
    success
    

    作为经验法则,通常,当我cd在脚本中使用命令时,我会测试目录更改是否成功:cd somewhere/ || exit. @dessert 提出了更合适的if ! cd dir; then exit 1; fi测试:但在所有情况下,为了保护脚本失败,最好使用@mrks 答案set -e中显示的选项。


    mkdir build; cd build; touch blank.txt
    

    ;是一个行分隔符,当在一行中写入几个单独的命令时使用它。


    请注意,在使用;或&&和时||,不必将命令写在一行 - 这在@allo 的答案中进行了说明。

    完全,IMO,在一行或单独的行中编写命令之间没有任何特殊的技术优势/差异。


    COMMAND="mkdir build && cd build && touch blank.txt"
    eval ${COMMAND}
    

    这里一个或多个命令(及其参数)被分组为一个变量的值,然后这个变量(参数)通过eval. 因此,您将能够通过仅在一处更改来更改将在某个脚本中多次执行的命令。

    假设您需要更改blank.txt创建文件的方式,例如,您可以通过以下方式更改相关行:

    COMMAND="mkdir build && cd build && echo 'test' > blank.txt"
    

    实际使用eval的优势alias在于,当有重定向、管道、逻辑运算符- 在所有控制流运算符 - 正在使用时。

    在大多数情况下,您可以使用functions而不是evalwhenalias不适用。此外,如果变量只包含一个命令,即CMD="cat"我们不需要eval,因为 Bash 分词将"$CMD" "$file1" "$file2"正确扩展。

    • 下面是一个示例,其中eval最简单的方法是执行一些命令自动化:跟踪“在最后一小时从日志文件中写入的行”是否可能?

    • 本节的先前版本(在评论中讨论)可在此处获得。

    • 59
  2. Bill K
    2019-10-22T14:14:03+08:002019-10-22T14:14:03+08:00

    到目前为止的答案解决了发生了什么/它是如何工作的,但我认为你在问“为什么”

    这样做的主要“原因”(对我来说)而不是在三行上键入它们是有时命令需要时间(有时是几分钟)并且您不想一直闲逛。

    例如,我可能会构建&&deploy&&启动我的应用程序,然后出去吃午饭。该过程可能需要 15 分钟才能完成。但是,由于我使用&&了 ,因此如果构建失败,它将不会部署——这样就可以了。

    Type-ahead 是一种替代方案,但它是不确定的,您可能无法看到您输入的内容(因此会出错),或者程序可能会吃掉 type-ahead(谢谢,grails!)。然后你吃完午饭回来,发现你还有两个很长的任务要开始,因为一个错字。

    另一种选择是编写一个小脚本或别名。不错的主意,但不允许有太多的灵活性,就像我可以:

    stop && build && test && deploy && start 
    

    或者我可以:

    stop && start
    

    或者任何数量的其他组合会很快用一堆标志污染脚本。

    即使您确实编写了一个脚本,您也很可能将它与其他脚本与&&.

    • 13
  3. pymym213
    2019-10-22T04:27:18+08:002019-10-22T04:27:18+08:00

    在 Linux 上组合命令非常有用。

    一个很好的例子可能是通过 ssh 重新启动远程网络接口(如果您更改了网络配置或其他东西......)。

    ifdown eth0 && ifup eth0
    

    这可以防止您物理上访问服务器以调出您最初 ssh 到的界面。(如果单独执行,您将无法执行。)ifup eth0ifdown eth0

    • 10
  4. Sergiy Kolodyazhnyy
    2019-10-23T00:36:08+08:002019-10-23T00:36:08+08:00

    命令有什么作用?

    为了了解原因,我们还需要了解正在做什么。脚本是连续的。在你的最后一个例子中:

    mkdir build
    cd build
    touch blank.txt
    

    cd build不管mkdir build成功与否都会被执行。当然如果mkdir fails,你会看到错误来自cd.

    mkdir build; cd build; touch blank.txt是一个顺序列表。这可以被认为与多个脚本行基本相同。Shell Grammar 将对此略有不同,但结果将与上述完全相同。同样,无论先前是否成功,都会执行命令。

    最后,还有

    mkdir build && cd build && touch blank.txt
    

    这是一个AND 列表- 由运算符分隔的一个或多个管道(或命令)的序列&&。此类列表中的命令以左关联性执行。这意味着,shell 将继续采用两个由 分隔的命令/管道&&,首先在左侧执行一个,只有在左侧成功时才运行右侧的一个(返回零退出状态)。

    在这个例子中,会发生什么?

    • shellmkdir build首先执行。
    • 上述命令成功(返回退出代码 0 ),cd build将运行
    • 再一次,让我们看看左结合性。... && touch blank.txt. 左边的东西&&成功了吗?如果是,运行touch blank.txt.

    为什么使用顺序列表与 AND 列表?

    当我们可以接受其中一个命令失败时,顺序列表mkdir build; cd build; touch blank.txt是有意义的。假设mkdir build已经存在。我们还是要cd进入build/目录和touch blank.txt. 当然,这里的缺点是可能会出现意想不到的结果。如果build没有设置执行位怎么办,这就是cd build失败的原因?这touch blank.txt将发生在我们当前的工作目录而不是预期的build/.

    现在考虑mkdir build && cd build && touch blank.txt。这在某种程度上更合乎逻辑,尽管有其自身的缺陷。如果build已经存在,很可能有人已经这样做了touch blank.txt,所以我们可能不想再这样做touch blank.txt了,因为这会修改其上的访问时间戳,这可能是不可取的。

    结论

    将命令放在同一行取决于命令的目的以及您要实现的目标。顺序列表可以简化输出,因为 shell 在命令完成之前不会重新显示提示。AND 列表允许有条件地执行命令,并且可以防止执行不必要的命令。底线是用户需要知道差异以及选择什么作为任务的正确工具。

    • 7
  5. rackandboneman
    2019-10-23T13:04:31+08:002019-10-23T13:04:31+08:00

    另一个原因可能是脚本是如何产生的:技术用户构建非常长的交互式命令行并反复扩展和测试它们直到它们按需要工作,然后将结果粘贴到文本文件中并拍打#!/bin/bash标题并不罕见超过它。有时,脚本的多个片段是通过该方法演变而来的。

    for i in以,链开头的长一行结构grep | cut | sed | xargs,大量使用&&和||,$(cat something)结构通常表明了这种起源。

    • 5
  6. WinEunuuchs2Unix
    2019-10-22T15:21:33+08:002019-10-22T15:21:33+08:00

    为什么我们有时喜欢使用它

    当我们在Ask Ubuntu中在这里写答案时,将它们放在一行中是很有帮助的,人们可以更轻松地剪切并粘贴到他们的终端中。例如:

    $ CurrDir=$PWD ; cd /bin ; ls -la dd ; cd "$CurrDir"
    
    -rwxr-xr-x 1 root root 72632 Mar  2  2017 dd
    

    如前所述,您可以使用&&相同的效果,但如果出现上述错误,您最终可能会进入错误的目录。在这种情况下;,最好&&不要测试成功:

    rick@alien:~/askubuntu$ CurrDir=$PWD && cd /bin && llllssss -la dd && cd "$CurrDir"
    
    llllssss: command not found
    
    rick@alien:/bin$ 
    

    为什么我们必须使用它

    在某些命令中,您必须将多行串在一起。一种情况是缩写if-commands-fi必须是一行。例如:

    $ [[ 2 -eq 2 ]] && { echo 2 equals 2 ; echo setting three to 3 ; three=3 ; }
    
    2 equals 2
    setting three to 3
    
    • 4
  7. allo
    2019-10-25T01:32:33+08:002019-10-25T01:32:33+08:00

    把所有东西都塞在一条线上有技术优势吗?

    这只是风格问题。没有技术优势。

    我认为其他人很好地解释了这三行的区别,但请注意,这并不意味着您需要将它们放在一行上。

    foo &&
    bar
    

    做同样的事情foo && bar。你仍然需要小心,因为

    foo
    && bar
    

    不一样,但运行 foo 然后产生语法错误。大多数情况下的一般规则:当 shell 从语法中知道您的行不完整时,它允许您继续下一行。
    当第一行可以按原样执行时,它将被执行(下一行可能是也可能不是语法错误,因为缺少第一行)。

    当您仍然希望脚本更具可读性时,可以像这样转义换行符

    foo \
    && bar
    

    确保字符后没有空格\,因为它必须直接位于换行符之前。

    • 3
  8. mrks
    2019-10-25T08:32:59+08:002019-10-25T08:32:59+08:00

    这里的许多答案都谈到了安全性,例如,“如果cd失败会发生什么”?

    虽然结合诸如cd foo && rm *解决该问题的命令,但有一种更好的方法:

    采取这个文件夹结构:

    .
    ./foo
    ./foo/bar
    ./foo2
    ./foo2/bar2
    ./test.sh
    ./do_not_delete_me
    

    和以下脚本:

    find .
    cd notexisting
    rm *
    cd ../foo2
    rm *
    cd ..
    find .
    

    由于notexisting不存在,rm *将运行.并删除do_not_delete_me。

    但是,如果您使用 启动脚本set -e,它将因第一个失败的命令而中止:

    ./test.sh: line 4: cd: notexisting: No such file or directory

    如评论中所述,将其包含在 shebang: 中是有意义的#!/bin/bash -e。

    • 2

相关问题

  • 如何从命令行仅安装安全更新?关于如何管理更新的一些提示

  • 如何从命令行刻录双层 dvd iso

  • 如何从命令行判断机器是否需要重新启动?

  • 文件权限如何工作?文件权限用户和组

  • 如何在 Vim 中启用全彩支持?

Sidebar

Stats

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

    如何运行 .sh 脚本?

    • 16 个回答
  • Marko Smith

    如何安装 .tar.gz(或 .tar.bz2)文件?

    • 14 个回答
  • Marko Smith

    如何列出所有已安装的软件包

    • 24 个回答
  • Marko Smith

    无法锁定管理目录 (/var/lib/dpkg/) 是另一个进程在使用它吗?

    • 25 个回答
  • Martin Hope
    Flimm 如何在没有 sudo 的情况下使用 docker? 2014-06-07 00:17:43 +0800 CST
  • Martin Hope
    Ivan 如何列出所有已安装的软件包 2010-12-17 18:08:49 +0800 CST
  • Martin Hope
    La Ode Adam Saputra 无法锁定管理目录 (/var/lib/dpkg/) 是另一个进程在使用它吗? 2010-11-30 18:12:48 +0800 CST
  • Martin Hope
    David Barry 如何从命令行确定目录(文件夹)的总大小? 2010-08-06 10:20:23 +0800 CST
  • Martin Hope
    jfoucher “以下软件包已被保留:”为什么以及如何解决? 2010-08-01 13:59:22 +0800 CST
  • Martin Hope
    David Ashford 如何删除 PPA? 2010-07-30 01:09:42 +0800 CST

热门标签

10.10 10.04 gnome networking server command-line package-management software-recommendation sound xorg

Explore

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

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve