* 20231020 写这篇博文断断续续花了好几天,为了说明不同shell在执行同一脚本文件时的差别,我分别在csdn提供线上Linux环境 (使用的shell是zsh)和自己的电脑上(使用的shell是bash)做测试。功夫不负有心人,在其中一些实例中可以体现出zsh和bash的对脚本文件支持的差别,收获匪浅......
一、第一个shell脚本:hello world!
前面我们陆续介绍了与Linux shell编程有关的数据类型、数据运算、流程控制语句等基础知识,今天我们正式开始写shell脚本了。
我们学习某种编程语言,通常写的第一个程序就是输出hello world!,今天我们就编写和运行第一个shell脚本写的hello world!,假定脚本文件名为hello.sh。
二、 录入脚本文件hello.sh
脚本文件本质上是一个文本文件,我们有很多种方法可以来创建它,比如可以用vi或vim之类的文本编辑器,这类编辑器,对于用过DOS下编辑器的用户来说,上手起来比较容易,而对于只有windows使用经历的用户而言,刚开始用起来未必顺手。
所以我们这里直接在命令行来创建。
(一)使用 echo 命令 和 输出重定向 来创建脚本文件hello.sh
具体命令如下:
1.在zsh中测试
csdn @ edu in ~ [20:28:14]
$ ++echo "#! /bin/bash" > hello.sh++
csdn @ edu in ~ [20:31:32]
$ ++echo 'echo "My first shell script file:Hello world!"' >> hello.sh++
csdn @ edu in ~ [20:32:28]
$ ++echo "# My first shell script file ends." >> hello.sh++
csdn @ edu in ~ [20:32:53]
$
2.在bash中测试
user @ host : ~ $ ++echo '#! /bin/bash' > hello.sh++
user @ host : ~ $ ++echo 'echo "My first shell script file:Hello world"' >> hello.sh++
user @ host : ~ $ ++echo '# My first shell script file ends.' >> hello.sh++
3.需要注意的地方
使用这种方法创建脚本文件时,有一点不方便的地方是需要注意双引号和单引号的使用,有时需要使用转义符。
(二)使用cp命令 和 /dev/stdin 来创建脚本文件hello.sh
我们也可以使用命令 :
bash
cp /dev/stdin hello.sh
来录入hello.sh的内容。/dev/stdin 是Linux 系统中一个特殊的符号链接文件,指向当前进程的标准输入文件描述符,代表标准输入,比如键盘。
在输完所有shell脚本内容后,我们按Ctrl+Z键来结束。
但是用这种方法创建的脚本文件在执行时通常会遇到问题:
1.在zsh中测试
csdn @ edu in ~ [23:11:12]
$ ++cp /dev/stdin hello.sh++
++#! /bin/bash++
++echo "My first shell script file:Hello world!"++
++# My first shell script file ends.++
++^Z++[1] + 148 suspended cp /dev/stdin hello.sh
csdn @ edu in ~ [23:12:26] C:20
csdn @ edu in ~ [12:33:07] C:127
$ ++./hello.sh++
zsh: text file busy: ./hello.sh
2.在bash中测试
user @ host : ~ $ ++cp /dev/stdin hello.sh++
#! /bin/bash
echo "My first shell script file:Hello world!"
My first shell script file ends.
++^Z++
[1]+ 已停止 cp /dev/stdin hello.sh
user @ host : ~ $ ++./hello.sh++
bash: ./hello.sh: /bin/bash: 解释器错误: 文本文件忙
这是因为cp命令执行后,对应的进程并没结束,hello.sh仍处于被cp进程打开操作的状态。
解决的方法我们以后会介绍。
二、查看脚本文件hello.sh的内容
要查看脚本文件hello.sh的内容,方法同样有很多种。
(一)使用cat命令查看
我们可以使用命令
bash
cat hello.sh
来查看刚才输入的hello.sh 的内容:
1.在zsh中测试
csdn @ edu in ~ [23:12:26] C:20
$ ++cat hello.sh++
#! /bin/bash
echo "My first shell script file:Hello world!"
My first shell script file ends.
csdn @ edu in ~ [23:12:36]
2.在bash中测试
user @ host : ~ $ ++cat hello.sh++
#! /bin/bash
echo "My first shell script file:Hello world!"
My first shell script file ends.
user @ host : ~ $
(二)使用cp命令 和 /dev/stdout来查看
/dev/stdout 是Linux 系统中一个特殊的符号链接文件,指向当前进程的标准输出文件描述符,代表标准输出,比如显示器屏幕。
1.在zsh中测试
csdn @ edu in ~ [21:11:30]
$ ++cp hello.sh /dev/stdout++
#! /bin/bash
echo "My first shell script file:Hello world!"
My first shell script file ends.
csdn @ edu in ~ [21:11:46]
$
2.在bash中测试
user @ host : ~ $ ++cp hello.sh /dev/stdout++
#! /bin/bash
echo "My first shell script file:Hello world"
My first shell script file ends.
user @ host : ~ $
三、shell脚本解说
在上面的hello.sh中,共有三行:
bash
#! /bin/bash
echo "My first shell script file:Hello world!"
# My first shell script file ends.
我们逐行说明。
(一)第一行:shebang或hashbang语句:指定脚本解释器
第一行是
bash
#! /bin/bash
1.shebang或hashbang语句的作用
以#! 开头,通常称为shebang或hashbang,用于指定默认情况下运行指定脚本的解释器路径,在上面的实例中我们指定的解释器是 /bin/bash。
这一行并不是必须的。如果一个脚本没有添加 shebang 行来指定解释器路径,则默认情况下系统会使用默认的 shell 来执行脚本。默认shell可以使用echo $0 或 echo $SHELL 查看。
由于目前可以在Linux系统上运行的shell有许多种:sh、bash、cshell、tcsh、zsh......尽管这些shell大多具有共同的语法,但它们确实有不同的语法或不同选项的处理方式,因此,同一个shell脚本文件在不同的shell中运行时可能会产生不同的结果。为了确保脚本文件获得预期的效果,我们建议为脚本指定解释器。
常见的解释器类型有:
#!/bin/sh
#!/bin/bash
#!/usr/bin/perl
#!/usr/bin/tcl
#!/bin/sed -f
#!/usr/awk -f
其中最常用、也是最常见的是 #!/bin/bash。
2.shebang或hashbang语句名称的由来
在Unix行话中,用sharp或hash(有时是mesh)来称呼字符#,用bang称呼字符!,因而shebang或 hashbang合起来就代表了这两个字符。到linux中也传承了这一传统。
(二)第二行:命令或语句
bash
echo "My first shell script file:Hello world!"
这一行是echo命令,用来显示字符串。在shell脚本文件中,除了第一行可能是shebang或hashbang语句外,接下来的语句可以是变是赋值命令,或者ls等命令,或者是if等流程控制语句。
(三)第三行:以#开头的注释
bash
# My first shell script file ends.
在shell脚本文件中,除了第一行以#! 开头的shebang或hashbang语句外,其他行中以#开始的内容均被视为注释。
关于注释,有两点说明:
1.注释的两种写法
有两种写法。
一种写法是像hello.sh的第3行这样将注释写成一个独立的行。
另一种写法是将注释可以直接写在要注释的命令之后。比如:
bash
echo "My first shell script file:Hello world!" # dispaly the string
其中 # dispaly the string 就是我们添加的注释。
2.一个脚本文件中可以有包含多个注释。
我们可以根据需要,在脚本文件中添加许多个注释,可以写在命令之后,也可以单独成行。
三、执行脚本文件hello.sh
通常来说,执行脚本文件有很多种方法 。我们先看看其中三种最常见的方法:
(一)shell解释器名称 脚本文件名
其实就是将脚本文件名作为命令参数传递给 shell解释器执行。
1.使用bash来执行
由于我们在hello.sh的shebang或hashbang语句中指定使用bash作为解释器,所以我们可以用命令
bash
bash hello.sh
csdn @ edu in ~ [23:12:36]
$++bash hello.sh++
My first shell script file:Hello world!
csdn @ edu in ~ [23:17:46]
2.使用sh来执行
我们也可以用命令
bash
sh hello.sh
来执行:
csdn @ edu in ~ [23:17:46]
$ ++sh hello.sh++
My first shell script file:Hello world!
csdn @ edu in ~ [23:19:27]
(二)脚本文件说明符
脚本文件说明符的格式是:
路径/脚本文件名
其中路径又分为绝对路径和相对路径。所以这种方式又可以细分为两种格式。
1.相对路径/脚本文件名
由于我们是在当前目录下创建了hello.sh,所以hello.sh的相对路径就是./,我们使用命令
./hello.sh
来运行看看。
(1)在zsh中测试
csdn @ edu in ~ [12:27:14] C:127
$ ++./hello.sh++
zsh: permission denied: ./hello.sh
看来是权限问题,我们使用ls -l命令查看 文件hello.sh的详细信息:
csdn @ edu in ~ [12:29:22] C:126
$ ++ls -l hello.sh++
-rw------- 1 csdn csdn 95 10月 20 12:23 hello.sh
我们只有读(r)写(w)权限,还没有执行(x)权限,我们使用命令
chmod a+x hello.sh
增加执行权限。
csdn @ edu in ~ [12:31:53] C:1
$ ++chmod a+x hello.sh++
csdn @ edu in ~ [12:32:53]
$ ++ls -l hello.sh++
-rwx--x--x 1 csdn csdn 95 10月 20 12:23 hello.sh
这下有执行权限(x)了。再试试看:
csdn @ edu in ~ [20:36:35]
$ ++./hello.sh++
My first shell script file:Hello world!
(2)在bash中测试
user @ host : ~ $ ++./hello.sh++
bash: ./hello.sh: 权限不够
user @ host : ~ $ ++ls -l hello.sh++
-rw--w---- 1 gxxc gxxc 94 10月 20 18:36 hello.sh
user @ host : ~ $ ++chmod +x hello.sh++
user @ host : ~ $ ++ls -l hello.sh++
-rwx-wx--x 1 gxxc gxxc 94 10月 20 18:36 hello.sh
user @ host : ~ $ ++./hello.sh++
My first shell script file:Hello world
user @ host : ~ $
2.绝对路径/脚本文件名
(1)在zsh中测试
我们先用pwd命令查看当前目录路径:
csdn @ edu in ~ [20:36:40]
$ ++pwd++
/home/csdn
可以看到,当前目录路径是/home/csdn,所以脚本文件的绝对路径文件说明符是/home/csdn/hello.sh。
那么我们可以通过命令:/home/csdn/hello.sh 来执行脚本:
csdn @ edu in ~ [20:38:39]
$ ++/home/csdn/hello.sh++
My first shell script file:Hello world!
(2)在bash中测试
user @ host : ~ $ ++pwd++
/tmp
user @ host : ~ $ ++/tmp/hello.sh++
My first shell script file:Hello world
user @ host : ~ $
在上面的例子中,当前目录的路径是/tmp,所以脚本文件的绝对路径文件说明符是/tmp/hello.sh。
所以我们可以通过命令:/tmp/hello.sh 来执行脚本。
(3)需要的注意地方
不管使用相对路径还是绝对路径来执行脚本文件,我们都要使用chmod 命令来为脚本文件增加执行(x)权限。
(三)利用source命令来执行。
有没有不用修改脚本文件权限又能执行脚本文件的方法呢?除了上面介绍的第一种方法:将脚本文件名作为命令参数传递给 shell解释器执行 外,我们还可以使用source命令来实现。
source 是 Shell 内置命令的一种,它会忽略脚本文件的权限,读取脚本文件,并依次执行其中的命令语句。
使用source命令执行脚本文件的格式是:
source 脚本文件说明符
也可以简写为:
. 脚本文件说明符
注意:简写命令格式中. 和 脚本文件说明符之间要用空格分隔。
1.在zsh中测试
csdn @ edu in ~ [20:38:50]
$ ++source ./hello.sh++
My first shell script file:Hello world!
csdn @ edu in ~ [20:47:56]
$ ++. ./hello.sh++
My first shell script file:Hello world!
csdn @ edu in ~ [20:48:25]
$ ++source hello.sh++
My first shell script file:Hello world!
csdn @ edu in ~ [20:49:07]
$ ++. hello.sh++
.: no such file or directory: hello.sh
csdn @ edu in ~ [20:49:15] C:127
可见,在zsh中,使用"source 脚本文件说明符"来执行脚本文件时,如果脚本文件在当前目录中,那么文件说明符中的路径可以省略。
使用". 脚本文件说明符" 这种简写格式来执行脚本文件时,脚本文件说明符的路径不能少。
2.在bash中测试
user @ host : ~ $ ++source hello.sh++
My first shell script file:Hello world
user @ host : ~ $ ++source ./hello.sh++
My first shell script file:Hello world
user @ host : ~ $ ++. hello.sh++
My first shell script file:Hello world
user @ host : ~ $ ++. ./hello.sh++
My first shell script file:Hello world
可见,在bash中,不管使用"source 脚本文件说明符"还是". 脚本文件说明符" 这种简写格式来执行脚本文件时,如果脚本文件在当前目前下,那么文件说明符中的路径都可以省略。
对比可见bash用起来更方便一些,bash能成为最流行的shell,这是其中的原因之一。