Contents

从单个命令行提示符运行多行命令

1. 概述

单行命令语句是 Linux 命令行的常态。但是,有时我们可能需要,或者只是觉得它很有效,从提示符运行多个命令。

在本教程中,我们将了解从单个命令行提示符运行多行命令的各种方法。

2. 多行代码技术

我们可以使用多种技术,例如:

  • 在行尾使用反斜杠进行分段
  • 用括号括起来
  • 限制在花括号内
  • 使用EOF 标签
  • 使用双与号 ( && ) 或分号 ( ; ) 运算符
  • 最可靠的是,编写脚本

让我们详细看看每一个。

2.1. 使用反斜杠

反斜杠 ( \ ) 是一个转义字符,指示 shell 不解释下一个字符。如果下一个字符是换行符,shell 会将该语句读取为尚未到达其结尾。这允许一个语句跨越多行。

这是一种有用的技术,可以将冗长的命令分成包含在 shell 会话窗口中的可读语句。

反斜杠还将命令语句分解为可理解的部分。因此,它们可用于将复杂的命令分解为其单独的操作。反斜杠甚至允许我们在一个提示符下在多行上执行多个命令。

让我们看一个使用反斜杠分割冗长复杂命令的示例:

$ find /etc -exec grep\
>'[0-9][0-9]*[.][0-9][0-9] \
> *[.][0-9][0-9]*[0-9][0-9]*' {} \;

2.2. 使用括号

括号在主 shell 会话中创建一个子 shell,并在该子 shell 中运行命令列表。即使子 shell 从主 shell 会话中导入变量,它也不会导出在其中创建的新变量,而是将它们的使用限制在自己的范围内。

一旦子shell 完成执行,这些新变量将不复存在。因此,即使没有变量声明,子shell 也可以从单个命令提示符运行多个命令

让我们看一个带括号的子shell的例子:

$ a=45
$ b=23
$ (
> c=`expr $a + $b`
> echo $c
> d=`expr $c + $a`
> echo $d
> )
68
113
$ echo $d
 
$ echo $c
 
$

我们可以看到子shell中声明的变量在外壳中是空的。

2.3. 使用花括号

花括号*{ }*常用于 shell 命令中,用于构建数组或实现参数扩展。但是,我们也可以通过将它们括在花括号中来从单个提示符运行一组命令

与开始子 shell 的括号不同,花括号在当前 shell 环境中运行这些命令

这意味着不仅主 shell 会话的导出变量可以被花括号中的部分访问;花括号内的命令也将它们的变量导出到主 shell 会话

$ a=60
$ b=45
$ {
> c=`expr $a + $b`
> echo $c
> d=`expr $c + $a`
> echo $d
> }
105
165
$ echo $c
105
$ echo $d
165

我们可以看到,花括号内声明的那些变量在花括号外仍然有效。

2.4. 使用EOF 标签

虽然EOF是此方法的默认文本,但Here TagHere Document是正式名称。此标记指示 shell 环境读取所有输入,直到到达相同的分隔符或标记。shell 环境可以是任何已知的 Linux shell — 即bashshcshtcshzshksh。因此,如果word 是Here 标记,shell 将读取重定向到它的所有输入,直到word再次出现。

注意:我们不能为Here Tags中的变量赋值,但我们可以处理导入的变量。

让我们看一个例子:

$ a=50
$ b=60
$ sh << word
> echo "Equation: a + b = 110"
> echo $(($a + $b))
> echo ""
> echo "Inside Here Tag, Assignment c=110"
> c=`expr $a + $b`
> echo $c
> word
Equation: a + b = 110
110
Inside Here Tag, Assignment c=110
$ echo "Outside Here Tag, Assignment c=110"
$ echo $c

我们看到,尽管在它之前处理了相同的算术运算,但新变量c没有收到任何值。

从历史上看,默认使用的文本是EOF—— “文件结束”的首字母缩写词,适合此类活动。STOP也被广泛使用,尽管EOF更流行且更具描述性。

我们可以自由使用任何单词、首字母缩写词或语法作为分隔符。但是,坚持使用EOFSTOP更为明智。它们对于这种方法是显而易见的,并且不太可能将它们误认为是其他命令。

让我们看一个使用EOF ( Here )标签的示例,重定向到Bash shell:

$ a=50
$ b=60
$ bash << EOF
> echo $(( $a + $b ))
> EOF
110

现在让我们看一下相同的示例,但重定向到Bourne shell

$ a=50
$ b=60
$ sh << EOF
> echo $(( $a + $b ))
> EOF
110

我们看到语法和结果是一样的。

2.5. 使用双 & 号

双 & 号 ( && ) 是一个布尔运算符,当且仅当前一个命令或语句没有错误执行时,它才允许执行命令。此运算符在处理顺序命令时很有用,这些命令的结果决定了下一个命令的执行。

*&&运算符通常用于在发出 cd 后连接任务 。因此,&&*运算符在减少打字和简化我们的逻辑方面进一步有益:

$ echo "The beginning of good things to come" > ThingsHeard.txt &&
> cat ThingsHeard.txt &&
> echo "Greater still, things to be done" >> ThingsHeard.txt &&
> cat ThingsHeard.txt &&
> cd txt &&
> echo "txt directory is non-existent" &&
> echo "These last two lines won't appear"
The Beginning of good things to come
The Beginning of good things to come
Greater still, things to be done
bash: cd: txt: No such file or directory

我们看到后续命令在遇到错误语句后仍未处理。

2.6. 使用分号

分号 ( ; ) 类似于*&&*运算符,用于定义顺序命令列表。但是,分号是命令分隔符而不是相邻的运算符。它允许执行一组按顺序列出的命令,而不管前面命令的结果如何。因此,当命令不相互依赖时,分号很有用

$ cd doc ; cd txt ; echo "txt directory is non-existent" ; echo "sequential commands are not bothered" 
bash: cd: txt: No such file or directory
txt directory is non-existent
sequential commands are not bothered

请注意,尽管有错误的语句,但仍执行了所有命令。

2.7. 结合技术

到目前为止,我们讨论的每种方法都有其优点和局限性。但是,通过结合部分或全部这些方法,我们可以克服它们的局限性。例如:

  • ( *&&)*和 ( ; ) 可以执行多行代码,该代码运行依赖于然后独立于先前语句的命令
  • 子shell 可以包含大括号或EOF 标记中列出的命令
  • 花括号可以包含子外壳和/或EOF 标记
  • EOF 标记可以包含子shell 和花括号
  • 一个子shell 可以在其中包含另一个子shell
  • 花括号可以嵌套其他花括号
  • EOF标签可以包含其他EOF标签

另外,让我们注意也有一些限制:

  • 所有其他技术都可以嵌套反斜杠技术
  • 但是,反斜杠技术不能在其中嵌套除双与号 ( && )之外的其他技术
  • ** Here 标记( EOF ) 只能从其最近的 shell 会话中导入**变量。因此,如果我们将Here 标记嵌套在花括号或子 shell 中,它将从这些会话中导入变量。它不会从之前的任何其他会话导入,包括主 shell 会话

我们来看一个嵌套多行代码的例子:

$ a=20
$ b=15
$ {
> c=`expr $a + $b`
> echo $c
> echo -e "\nAn example of using the backslash \
> within curly braces as a nested multi-line code."
> 
> (
> d=`expr $c + $a`
> echo $d
> 
> sh << EOF
> 
> echo $(($c + $b))
> 
> cd txt &&
> echo -e "\n txt directory is non-existent, therefore, \
> this statement will not display."
> 
> EOF
> )
> 
> echo -e "\nSince the variable d was declared in a subshell \
> will it display outside the subshell? Let's see:"
> 
> echo $d
> 
> echo "No it didn't"
> 
> echo -e "\nWill the variable e print? \
> It was nested inside a Here tag, inside \
> a sub shell."
> 
> echo $e
> 
> bash << EOF
> 
> {
> cd doc &&
> echo "Greater still, the opportunities." >> ThingsHeard.txt &&
> cat ThingsHeard.txt
> (
> echo -e "\nA nested backslash statement \
> within a subshell, within curly braces."
> 
> cd txt ;
> 
> echo -e "\nEven though the directory txt is non-existent, \
> this statement will still print since the previous command \
> was separated with a semicolon (;)."
> 
> )
> }
> EOF
> }

让我们看看这些命令的输出:

35
An example of using the backslash within curly braces as a nested multi-line code.
55
50
sh: 5: cd: can't cd to txt
Since the variable d was declared in a subshell will it display outside the subshell? Let's see:
No it didn't
Will the variable e print? It was nested inside a Here tag, inside a sub shell.
The Beginning of good things to come
Greater still, the opportunities.
A nested backslash statement within a subshell, within curly braces.
bash: line 11: cd: txt: No such file or directory
Even though the directory txt is non-existent, this statement will still print since the previous command was separated with a semicolon (;).

2.8. 编写 Shell 脚本

最后,运行多行 shell 代码的最佳技术是脚本。使用 shell 脚本,我们可以编辑和调整我们的命令,而无需重写它们。此外,它们允许我们使用“一次编写,多次运行”的原则来处理重复性任务。此外,当我们处理语法或逻辑复杂的命令时,脚本是最佳选择。

当然,我们可以在脚本中使用前面提到的技术。让我们看一个包含多行代码的脚本示例:

#!/bin/bash
#########################################
# This is a script that uses multi-line #
# code methods within it		#
#########################################
a=$RANDOM
b=$RANDOM
{
c=`expr $a + $b`
echo $c
echo -e "\nA backslash multi-line code example \
within a script.\n"
(
d=`expr $c + $a`
echo $d
echo
cd doc &&
cat ThingsHeard.txt
echo 
cd txt ;
echo -e "\n txt directory is non-existent \
yet the next command will still run because \
the semicolon is used as a separator.\n"
cat ThingsHeard.txt
)
bash << EOF
echo -e "\nA Here tag multi-line code example \
nested within curly braces, in a script."
EOF
}

让我们看一下在花括号中调用的上述脚本的示例:

${
> a=8
> b=9
> t=`expr $a + $b`
> echo $t
> echo
> ./multiline.sh 
> }

现在,让我们看看结果输出:

17
37302
A backslash multi-line code example within a script.
53464
The Beginning of good things to come
Greater still, the opportunities.
./multiline.sh: line 31: cd: txt: No such file or directory
 txt directory is non-existent yet the next command will still run because the semicolon is used as a separator.
The Beginning of good things to come
Greater still, the opportunities.
A Here tag multi-line code example nested within curly braces, in a script.