彻底掌握shell编程

什么是 shell

  • Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。
  • Shell 既是一种命令语言,又是一种程序设计语言。
  • Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问 Linux 内核的服务。

Ken Thompson 的 sh 是第一种 Unix Shell,Windows Explorer 是一个典型的图形界面 Shell。

什么是 shell 脚本

Shell 脚本(shell script),是一种为 shell 编写的脚本程序,一般文件后缀为 .sh

业界所说的 shell 通常都是指 shell 脚本,但 shell 和 shell script 是两个不同的概念。

Shell 环境

Shell 编程跟 java、php 编程一样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了。

Shell 的解释器种类众多,常见的有:

  • sh - 即 Bourne Shell。sh 是 Unix 标准默认的 shell。
  • bash - 即 Bourne Again Shell。bash 是 Linux 标准默认的 shell。
  • fish - 智能和用户友好的命令行 shell。
  • xiki - 使 shell 控制台更友好,更强大。
  • zsh - 功能强大的 shell 与脚本语言。

指定脚本解释器

在 shell 脚本,#! 告诉系统其后路径所指定的程序即是解释此脚本文件的 Shell 解释器。#! 被称作shebang(也称为 Hashbang )

所以,你应该会在 shell 中,见到诸如以下的注释:

  • 指定 sh 解释器
#!/bin/sh
  • 指定 bash 解释器
#!/bin/bash

注意

上面的指定解释器的方式是比较常见的,但有时候,你可能也会看到下面的方式:

#!/usr/bin/env bash

这样做的好处是,系统会自动在 PATH 环境变量中查找你指定的程序(本例中的bash)。相比第一种写法,你应该尽量用这种写法,因为程序的路径是不确定的。这样写还有一个好处,操作系统的PATH变量有可能被配置为指向程序的另一个版本。比如,安装完新版本的bash,我们可能将其路径添加到PATH中,来“隐藏”老版本。如果直接用#!/bin/bash,那么系统会选择老版本的bash来执行脚本,如果用#!/usr/bin/env bash,则会使用新版本。

模式

shell 有交互和非交互两种模式。

交互模式

简单来说,你可以将 shell 的交互模式理解为执行命令行。

看到形如下面的东西,说明 shell 处于交互模式下:

user@host:~$

接着,便可以输入一系列 Linux 命令,比如 lsgrepcdmkdirrm 等等。

非交互模式

简单来说,你可以将 shell 的非交互模式理解为执行 shell 脚本。

在非交互模式下,shell 从文件或者管道中读取命令并执行。

当 shell 解释器执行完文件中的最后一个命令,shell 进程终止,并回到父进程。

可以使用下面的命令让 shell 以非交互模式运行:

sh /path/to/script.sh
bash /path/to/script.sh
source /path/to/script.sh
./path/to/script.sh

上面的例子中,script.sh是一个包含 shell 解释器可以识别并执行的命令的普通文本文件,shbash是 shell 解释器程序。你可以使用任何喜欢的编辑器创建script.sh(vim,nano,Sublime Text, Atom 等等)。

其中,source /path/to/script.sh 和 ./path/to/script.sh 是等价的。

除此之外,你还可以通过chmod命令给文件添加可执行的权限,来直接执行脚本文件:

chmod +x /path/to/script.sh #使脚本具有执行权限
/path/to/test.sh

这种方式要求脚本文件的第一行必须指明运行该脚本的程序,比如:

💻 『示例源码』

#!/usr/bin/env bash
echo "Hello, world!"

上面的例子中,我们使用了一个很有用的命令echo来输出字符串到屏幕上。

基本语法

解释器

前面虽然两次提到了#! ,但是本着重要的事情说三遍的精神,这里再强调一遍:

在 shell 脚本,#! 告诉系统其后路径所指定的程序即是解释此脚本文件的 Shell 解释器。#! 被称作shebang(也称为 Hashbang )

#! 决定了脚本可以像一个独立的可执行文件一样执行,而不用在终端之前输入shbashpythonphp等。

# 以下两种方式都可以指定 shell 解释器为 bash,第二种方式更好
#!/bin/bash
#!/usr/bin/env bash

注释

注释可以说明你的代码是什么作用,以及为什么这样写。

shell 语法中,注释是特殊的语句,会被 shell 解释器忽略。

  • 单行注释 - 以 # 开头,到行尾结束。
  • 多行注释 - 以 :<<EOF 开头,到 EOF 结束。

💻 『示例源码』

#--------------------------------------------
# shell 注释示例
# author:zp
#--------------------------------------------

# echo '这是单行注释'

########## 这是分割线 ##########

:<<EOF
echo '这是多行注释'
echo '这是多行注释'
echo '这是多行注释'
EOF

echo

echo 用于字符串的输出。

输出普通字符串:

echo "hello, world"
# Output: hello, world

输出含变量的字符串:

echo "hello, \"zp\""
# Output: hello, "zp"

输出含变量的字符串:

name=zp
echo "hello, \"${name}\""
# Output: hello, "zp"

输出含换行符的字符串:

# 输出含换行符的字符串
echo "YES\nNO"
#  Output: YES\nNO

echo -e "YES\nNO" # -e 开启转义
#  Output:
#  YES
#  NO

输出含不换行符的字符串:

echo "YES"
echo "NO"
#  Output:
#  YES
#  NO

echo -e "YES\c" # -e 开启转义 \c 不换行
echo "NO"
#  Output:
#  YESNO

输出重定向至文件

echo "test" > test.txt

输出执行结果

echo `pwd`
#  Output:(当前目录路径)

💻 『示例源码』

#!/usr/bin/env bash

# 输出普通字符串
echo "hello, world"
#  Output: hello, world

# 输出含变量的字符串
echo "hello, \"zp\""
#  Output: hello, "zp"

# 输出含变量的字符串
name=zp
echo "hello, \"${name}\""
#  Output: hello, "zp"

# 输出含换行符的字符串
echo "YES\nNO"
#  Output: YES\nNO
echo -e "YES\nNO" # -e 开启转义
#  Output:
#  YES
#  NO

# 输出含不换行符的字符串
echo "YES"
echo "NO"
#  Output:
#  YES
#  NO

echo -e "YES\c" # -e 开启转义 \c 不换行
echo "NO"
#  Output:
#  YESNO

# 输出内容定向至文件
echo "test" > test.txt

# 输出执行结果
echo `pwd`
#  Output:(当前目录路径)

printf

printf 用于格式化输出字符串。

默认,printf 不会像 echo 一样自动添加换行符,如果需要换行可以手动添加 \n

💻 『示例源码』

# 单引号
printf '%d %s\n' 1 "abc"
#  Output:1 abc

# 双引号
printf "%d %s\n" 1 "abc"
#  Output:1 abc

# 无引号
printf %s abcdef
#  Output: abcdef(并不会换行)

# 格式只指定了一个参数,但多出的参数仍然会按照该格式输出
printf "%s\n" abc def
#  Output:
#  abc
#  def

printf "%s %s %s\n" a b c d e f g h i j
#  Output:
#  a b c
#  d e f
#  g h i
#  j

# 如果没有参数,那么 %s 用 NULL 代替,%d 用 0 代替
printf "%s and %d \n"
#  Output:
#   and 0

# 格式化输出
printf "%-10s %-8s %-4s\n" 姓名 性别 体重kg
printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234
printf "%-10s %-8s %-4.2f\n" 杨过 男 48.6543
printf "%-10s %-8s %-4.2f\n" 郭芙 女 47.9876
#  Output:
#  姓名     性别   体重kg
#  郭靖     男      66.12
#  杨过     男      48.65
#  郭芙     女      47.99

printf 的转义符

序列 说明
\a 警告字符,通常为 ASCII 的 BEL 字符
\b 后退
\c 抑制(不显示)输出结果中任何结尾的换行字符(只在%b 格式指示符控制下的参数字符串中有效),而且,任何留在参数里的字符、任何接下来的参数以及任何留在格式字符串中的字符,都被忽略
\f 换页(formfeed)
\n 换行
\r 回车(Carriage return)
\t 水平制表符
\v 垂直制表符
\\ 一个字面上的反斜杠字符
\ddd 表示 1 到 3 位数八进制值的字符。仅在格式字符串中有效
\0ddd 表示 1 到 3 位的八进制值字符

变量

跟许多程序设计语言一样,你可以在 bash 中创建变量。

Bash 中没有数据类型,bash 中的变量可以保存一个数字、一个字符、一个字符串等等。同时无需提前声明变量,给变量赋值会直接创建变量。

变量命名原则

  • 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。
  • 中间不能有空格,可以使用下划线(_)。
  • 不能使用标点符号。
  • 不能使用 bash 里的关键字(可用 help 命令查看保留关键字)。

声明变量

访问变量的语法形式为:${var} 和 $var 。

变量名外面的花括号是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,所以推荐加花括号。

word="hello"
echo ${word}
# Output: hello

只读变量

使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。

rword="hello"
echo ${rword}
readonly rword
# rword="bye"  # 如果放开注释,执行时会报错

删除变量

使用 unset 命令可以删除变量。变量被删除后不能再次使用。unset 命令不能删除只读变量。

dword="hello"  # 声明变量
echo ${dword}  # 输出变量值
# Output: hello

unset dword    # 删除变量
echo ${dword}
# Output: (空)

变量类型

  • 局部变量 - 局部变量是仅在某个脚本内部有效的变量。它们不能被其他的程序和脚本访问。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值