shell编程基础
简介
shell脚本通常是一个以shebang1起始的文本文件,如下所示:
#!/bin/bash
shebang是一个文本行,其中#!
位于解释器路径之前。/bin/bash
是Bash的解释器命令路径。
有两种运行脚本的方式。一种是将脚本作为bash
的命令行参数,另一种是授予脚本执行权限,将其变为可执行文件。
1.将脚本作为命令行参数时的运行方式如下:
bash test.sh #假设脚本位于当前目录下
如果将脚本作为bash
的命令行参数来运行,那么就用不着脚本中的shebang了。
2.授予脚本执行权限,将其变为可执行文件:
chmod a+x test.sh
./test.sh
内核会读取脚本的首行并注意到shebang为#!/bin/bash
。它识别出/bin/bash
并在内部像这样执行该脚本:
/bin/bash test.sh
当启动shell时,它一开始会执行一组命令来定义诸如提示文本、颜色等各类设置。这组命令来自位于用户主目录2中的脚本文件~/.bashrc
(对于登录shell则是~/.bash_profile
3)。Bash还维护了一个历史记录文件~/.bash_history
,用于保存用户运行过的命令。
终端打印
echo
是用于终端打印的基本命令。在默认情况下,echo
在每次调用后会添加一个换行符。
echo "Welcome to WuHan"
Welcome to WuHan
不带双引号的文本或使用单引号也可以得到同样的输出结果:
echo Welcome to China ; echo 'Welcome to WuHan'
Welcome to China
Welcome to WuHan
这些方法看起来相似,但各有一些特殊用途和副作用。思考下面这行命令:
echo "Welcome to WuHan !"
-bash: !": event not found
如果需要打印!
,那就不要将其放入双引号中,或者你可以在其之前加上一个特殊的转义字符(\
)将!
转义:
"Welcome to WuHan \!"
Welcome to WuHan \!
或者不带引号4:
echo Welcome to WuHan !
Welcome to WuHan !
或使用单引号5:
echo 'Welcome to WuHan !'
Welcome to WuHan !
另一个可用于终端打印的命令是printf
。printf
使用的参数和C语言中的printf
函数一样。
printf "hello WuHan"
hello WuHan
printf
使用引用文本或由空格分隔的参数。我们可以在printf
中使用格式化字符串,还可以指定字符串的宽度、左右对齐方式等。在默认情况下,printf
并不像echo
命令一样会自动添加换行符,我们必须在需要的时候手动添加,比如在下面的脚本中:
#!/bin/bash
#文件名: printf_fund.sh
printf "%-5s %-10s %-4s\n" No 指数名称 今日PE
printf "%-5s %-10s %-4.2f\n" 1 沪深300 15.37
printf "%-5s %-10s %-4.2f\n" 2 上证综指 15.90
printf "%-5s %-10s %-4.2f\n" 3 中证500 29.83
我们会得到如下格式化的输出:
No 指数名称 今日PE
1 沪深300 15.37
2 上证综指 15.90
3 中证500 29.83
%s
、%c
、%d
和%f
都是格式替换符(format substitution character),其所对应的参数可以置于带引号的格式字符串之后。
%-5s
指明了一个格式为左对齐且宽度为5的字符串替换(-
表示左对齐)。如果不用-
指定对齐方式,字符串就采用右对齐形式。宽度指定了保留给某个变量的字符数。对Name而言,保留宽度是10。因此,任何Name字段的内容都会被显示在10字符宽的保留区域内,如果内容不足10个字符,余下的则以空格符填充。
对于今日PE字段,将其格式化为%-4.2f
,其中.2
指定保留2
个小数位。注意,在每行格式字符串后都有一个换行符(\n
)。
使用echo
和printf
的命令选项时,要确保选项应该出现在命令行内所有字符串之前,否则Bash会将其视为另外一个字符串。
1.在echo中转义换行符
在默认情况下,echo
会将一个换行符追加到输出文本的尾部。可以使用选项-n
来忽略结尾的换行符。echo
同样接受双引号字符串内的转义序列作为参数。如果需要使用转义序列,则采用echo –e "包含转义序列的字符串"
这种形式。
echo -e "1\t2\t3"
1 2 3
2. 打印彩色输出
要打印彩色文本,可输入如下命令:
echo -e "\e[1;31m This is red text \e[0m"
This is red text
\e[1;31
将颜色设为红色,\e[0m
将颜色重新置回。只需要将31
替换成想要的颜色码就可以了。每种颜色都有对应的颜色码。比如:
颜色 | 颜色码 |
---|---|
重置 | 0 |
黑色 | 30 |
红色 | 31 |
绿色 | 32 |
黄色 | 33 |
蓝色 | 34 |
洋红 | 35 |
青色 | 36 |
白色 | 37 |
要设置彩色背景,可将上方表格中除重置一行的颜色码数值加10,就是对应的彩色背景的颜色码。例如要打印绿色背景,可输入如下命令:
echo -e "\e[1;42m Green Background \e[0m"
Green Background
变量与环境变量
在Bash中,每一个变量的值都是字符串。无论你给变量赋值时有没有使用引号,值都会以字符串的形式存储。有一些特殊的变量会被shell环境和操作系统环境用来存储一些特别的值,这类变量就被称为环境变量。
变量采用常见的命名方式进行命名。当应用程序执行时,它接收一组环境变量。可以使用env
命令查看所有与终端相关的环境变量。对于进程来说,其运行时的环境变量可以使用下面的命令来查看:
cat /proc/$PID/environ
其中,将PID设置成相关进程的进程ID(PID总是一个整数)。
假设有一个叫做top的应用程序正在运行。我们可以使用pgrep
命令获得top的进程ID:
pgrep top
1288
那么,你就可以通过以下命令获得与该进程相关的环境变量:
cat /proc/1288/environ # 限于篇幅下面的环境变量有省略
XDG_SESSION_ID=91326VIRTUALENVWRAPPER_SCRIPT=/usr/local/python3/bin/virtualenvw...
上面的命令返回一个包含环境变量以及对应变量值的列表。每一个变量以name=value的形式来描述,彼此之间由null字符(\0
)分隔。如果你将\0
替换成\n
,那么就可以将输出重新格式化,使得每一行显示一组“变量=值”。替换可以使用tr
命令来实现:
cat /proc/1288/environ | tr '\0' '\n'
XDG_SESSION_ID=91326
VIRTUALENVWRAPPER_SCRIPT=/usr/local/python3/bin/virtualenvwrapper.sh
VIRTUALENVWRAPPER_PROJECT_FILENAME=.project
...
变量赋值
var=value
var
是变量名,value
是赋给变量的值。如果value
不包含任何空白字符(例如空格),那么它就不需要使用引号进行引用,否则必须使用单引号或双引号。
注意:var = value
不同于var=value
。把var=value
写成var = value
是一个常见的错误,但前者是赋值操作,后者则是相等操作。
在变量名之前加上$
前缀就可以打印出变量的内容:
var="value" # 给变量var赋值
echo $var # 可写为:echo ${var}
value
还可以在printf
或echo
命令的双引号中引用变量值:
#!/bin/bash
#文件名:variables.sh
fruit=banana
count=8
echo "We have $count ${fruit}(s)"
输出:
bash variables.sh
We have 8 banana(s)
环境变量是未在当前进程中定义,而从父进程中继承而来的变量。例如环境变量HTTP_PROXY
,它定义了互联网连接应该使用哪个代理服务器。
该环境变量通常被设置成:
HTTP_PROXY=192.168.1.23:3128
export HTTP_PROXY
export
命令用来设置环境变量。至此之后,从当前shell脚本执行的任何应用程序都会继承这个变量。我们可以按照自己的需要,在执行的应用程序或者shell脚本中导出特定的变量在默认情况下,有很多标准环境变量可供shell使用。
PATH
就是其中之一。通常,变量PATH
包含:
echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/usr/local/python3/bin
在给出所要执行的命令后,shell会自动在PATH
环境变量所包含的目录列表中(各目录路径之间以冒号分隔)查找对应的可执行文件。PATH通常定义在/etc/environment
或/etc/profile
或~/.bashrc
中。如果需要在PATH
中添加一条新路径,可以使用6:
export PATH="$PATH:/home/user/bin"
或使用:
PATH="$PATH:/home/user/bin"
export PATH
这样,我们就将/home/user/bin
添加到了PATH
中:
echo $PATH
/home/slynux/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr
/games:/home/user/bin
还有一些众所周知的环境变量:HOME
、PWD
、USER
、UID
、SHELL
等。
shebang这个词其实是两个字符名称的组合。在Unix的行话里,用sharp或hash(有时候是mesh)来称呼字符“#”,用bang来称呼惊叹号“!”,因而shebang合起来就代表了这两字符。详情请参考:Unix ↩︎
~
表示主目录,它通常是/home/user
,其中user是用户名,如果是root用户,则为/root
。 ↩︎登录shell是登录主机后获得的那个shell。如果登录图形界面环境(比如GNOME、KDE等)后打开了一个shell,就不是登录shell。 ↩︎
使用不带引号的
echo
时,没法在所要显示的文本中使用分号(;
),因为分号在Bash shell中被用作命令定界符。 ↩︎变量替换在单引号中无效。 ↩︎
使用单引号时,变量不会被扩展(expand),将依照原样显示。这意味着:
$ echo '$var' will print $var
但如果变量var
已经定义过,那么$ echo "$var"
会打印出该变量的值;如果没有定义过,则什么都不打印。 ↩︎