Mic*_*ann 6 command-line bash scripts
我正在学习 Linux Essentials 课程,并且在我进入脚本章节之前一直表现良好。我根本不明白这些概念。想知道是否有人可以将以下内容分解为极其简单的术语,或者为我提供更好的参考来学习它。我目前正在使用 netacad 的课程。
来自教科书(格式略有变化):
除了您设置的变量之外,还有一些特殊变量。您可以将参数传递给脚本:
Run Code Online (Sandbox Code Playgroud)#!/bin/bash echo "Hello $1"美元符号后跟数字 N 对应于传递给脚本的第 N 个参数。如果您调用上面的示例,
./test.sh输出将是 Hello Linux。该$0变量包含脚本本身的名称。程序运行后,无论是二进制还是脚本,它都会返回一个退出代码,该代码是 0 到 255 之间的整数。您可以通过
$?变量进行测试,以查看上一个命令是否成功完成。
我知道如何分配变量,他们与如何工作$,但整个问题同$0和$1-我只是不明白这一点。
任何帮助将非常感激。
书中的描述是错误的(或至少遗漏了一些东西)。要让该脚本打印“Hello Linux”,您可以像这样运行它:
./test.sh Linux
Run Code Online (Sandbox Code Playgroud)
如果你用 just 运行它./test.sh,那么它只会打印“Hello”,因为没有第一个参数并且$1没有定义。另一方面,假设你是这样运行的:
./test.sh foo bar baz
Run Code Online (Sandbox Code Playgroud)
然后在脚本中,$0将“./test.sh”,$1将是‘富’,$2将是‘酒吧’,并且$3将‘巴兹’。
至于$?,请考虑以下脚本片段:
ls nonexistentfile.txt
echo "The exit status of ls was: $?"
echo "The exit status of echo (the first one) was: $?"
Run Code Online (Sandbox Code Playgroud)
运行时会打印如下内容:
ls: nonexistentfile.txt: No such file or directory
The exit status of ls was: 1
The exit status of echo (the first one) was: 0
Run Code Online (Sandbox Code Playgroud)
该ls命令无法列出 nonexistentfile.txt(因为它不存在),因此它会为此打印一条错误消息,并以非零状态退出以指示出现问题。第一个echo命令打印退出状态 ( $?),并且由于它成功执行了此操作,因此它以零状态退出。当第二个echo命令运行时,它$?从第一个echo命令获取,因此它打印“0”。
顺便说一句,很多命令只使用 0(成功)或 1(某种失败)的退出状态,但有些命令使用不同的失败状态来准确指示出了什么问题。这是curl手册页的摘录:
EXIT CODES
There are a bunch of different error codes and their corresponding
error messages that may appear during bad conditions. At the time of
this writing, the exit codes are:
1 Unsupported protocol. This build of curl has no support for this
protocol.
2 Failed to initialize.
3 URL malformed. The syntax was not correct.
...
88 FTP chunk callback reported error
89 No connection available, the session will be queued
90 SSL public key does not matched pinned public key
91 Invalid SSL certificate status.
92 Stream error in HTTP/2 framing layer.
Run Code Online (Sandbox Code Playgroud)
...因此使用的脚本curl可以检查$?以找出问题所在,并根据问题做出不同的响应。
$0是用于运行脚本的名称。$1, $2, 等等是脚本的位置参数,它们保存您在运行脚本时传递的命令行参数的值。
正如戈登戴维森所说,这本书的作者一定是想说跑步./test Linux会印刷Hello Linux。当你这样做时,./test进入特殊参数0,Linux进入第一个位置参数1。该脚本通过在第一个位置参数前面加上美元符号 ( $1) 来扩展它,就像您对变量所做的一样。如果您改为运行./test Hello Linux for Human Beings,则在脚本中,$1将扩展为Linux、$2至for、$3至Human和$4至Beings。
您可以编写一个简单的脚本来尝试一下:
#!/bin/bash
echo "\$0 expands to '$0'."
echo "\$1 expands to '$1'."
echo "\$2 expands to '$2'."
echo "\$3 expands to '$3'."
Run Code Online (Sandbox Code Playgroud)
(随心所欲。对于大于 的位置参数9,使用${ }参数扩展的形式,例如10通过编写扩展${10}。在处理许多位置参数的脚本中,@经常使用特殊参数,避免重复,但您可以如果您愿意,请暂时忽略它。)
尝试将其保存在文件中并将文件标记为可执行文件,您可以通过运行chmod +x simplewheresimple替换为文件名(如果不同)来执行此操作。然后,你可以使用类似的命令运行它./simple,./simple foo,./simple foo bar,等等。
您会注意到,当传递的命令行参数少于三个时,与未传递的参数对应的位置参数会扩展为空字符串。这就是当您尝试扩展未定义的 shell 参数时会发生的情况。此外,您会注意到,当传递更多命令行参数时,不会使用超过第三个的参数。这可能是您所期望的,因为脚本根本没有提到它们。
现在尝试运行./simple *。shell 扩展*到当前目录中的所有文件名,除了那些以 开头的文件名.,因此其中三个将显示为前三个位置参数(如果没有那么多,则更少)。您可以尝试使用其他 shell 扩展来运行它,例如./simple {5..10}.
您可以通过将包含空格的命令行参数括在引号中来传递它们。例如,尝试./simple 'foo bar' baz。请注意,$1扩展到foo bar这个时间,而不仅仅是扩展到foo。
由于 shell 执行各种扩展,因此传递给命令的命令行参数的数量并不总是很明显。查看每个参数是什么的一种简单方法是将命令替换为printf '[%s]\n'. 例如:
$ printf '[%s]\n' f*
[fonts]
[fstab]
[fuse.conf]
[fwupd]
Run Code Online (Sandbox Code Playgroud)
$ printf '[%s]\n' {1,3}{a..c}
[1a]
[1b]
[1c]
[3a]
[3b]
[3c]
Run Code Online (Sandbox Code Playgroud)
由于您最近才开始编写 shell 脚本,因此Bash 参考手册可能具有挑战性,您可能不想从头到尾阅读它。但我认为即使您认为自己是一个完整的初学者,它也是一种宝贵的资源。您可能会发现有关shell 参数的部分很有用,因为它从您已经知道的内容开始——shell 变量——然后转到特殊参数,例如?(人们通常称之为$?参数,因为这是您扩展它的方式)。对于 Bash 的一般学习,特别是在更介绍性的级别,我推荐这些页面,包括BashGuide。