从单个命令行提示符运行多行命令
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 Tag或Here Document是正式名称。此标记指示 shell 环境读取所有输入,直到到达相同的分隔符或标记。shell 环境可以是任何已知的 Linux shell — 即bash、sh、csh、tcsh、zsh或ksh。因此,如果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更流行且更具描述性。
我们可以自由使用任何单词、首字母缩写词或语法作为分隔符。但是,坚持使用EOF或STOP更为明智。它们对于这种方法是显而易见的,并且不太可能将它们误认为是其他命令。
让我们看一个使用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.