参考:Bash: How-To, Advanced Bash-Scripting Guide, nixCraft, Command Line Fu,
shell既可以交互式地执行用户输入的命令,也可以编写成脚本,shell按照一定的规则自动执行脚本中的命令。
shell脚本文件一般是下面的这种形式:
$ cat sample.sh
#!/bin/bash
echo "hello world!"
exit 0
注意:exit 0
表示该脚本的exit status。
使用sh
调用该脚本:
$ sh sample.sh
也可以先赋予脚本可执行权限,然后直接执行:
$ chmod +x sample.sh
$ ./sample.sh
*nix上的shell有很多种,本文仅基于bash和sh,列出基本的语法,重点关注容易出错的细节。
[TOP]
本地变量指用户自定义变量。
变量赋值:
$ name="Bill Bu"
变量赋值时的等号左右不能有空格。变量默认为字符串(不能进行算术计算),如果变量值包含空格,需要使用单引号或双引号。
命令的结果可以作为一个值赋予变量,这时应使用反引号或$()
包含命令;变量值中可以使用转义符\
。
变量叠加:
$ name="$name"ad
或者
$ name=${name}ad
命令代换:
$ VAR_DATE=`date`
注意:这里‘是反引号,不是单引号。
更常用的是
$ VAR_DATE=$(date)
表示将括号中命令的结果输出,赋值给VAR_DATE。
算术代换:
$ VAR=101
$ echo $(($VAR-1))
上文提到,变量赋值时默认为字符串,如果需要进行算术运算,可以将算术表达式用$(())
扩起来。$(())
中只能进行整数运算,可选的运算符只有+
,-
,*
,/
。注意:括号、变量和运算符之间均没有空格。
变量调用:
$ echo $name
变量查看:
$ set
变量删除:
$ unset name
本地变量可导出为环境变量:
$ export VARNAME
set
和unset
也适用于环境变量。
变量替换运算符:
${VAR:-word} # 如果VAR存在且非null,返回$VAR;否则,返回word。
${VAR:=word} # 如果VAR存在且非null,返回$VAR;否则,VAR=word,并返回$VAR。
${VAR:?word} # 如果VAR存在且非null,返回$VAR;否则,输出 VAR:message,并退出当前命令或脚本。
${VAR:+word} # 如果VAR存在且非null,返回word;否则,返回null。
如果省略:
,则表示“如果VAR存在”。
查询:
$ env
临时添加PATH变量:
$ PATH="$PATH":/home/name/sh
PATH | 可执行文件的搜索路径 |
SHELL | 当前shell |
TERM | 当前终端类型 |
LANG | 语言和locale,决定编码,时间、货币等显示格式 |
HOME | 当前用户主目录 |
[TOP]
常用的条件判断形式为:
[ EXPRESSION ]
如果表达式成立,返回0,否则返回非0。注意:括号与表达式之间、表达式中各命令、参数之间都必须加空格。
$ [ 1 = 2 ]
$ echo $?
1
$ [ 1 = 1 ]
$ echo $?
0
这里,$?
表示上一命令的执行结果,若命令成功则为0,否则非0。
n1 -eq n2 |
n1等于n2 |
n1 -ge n2 |
n1大于等于n2 |
n1 -gt n2 |
n1大于n2 |
n1 -le n2 |
n1小于等于n2 |
n1 -lt n2 |
n1小于n2 |
n1 -ne n2 |
n1不等于n2 |
这些表达式中,e-equal
,g-greater
,l-less
,t-than
。
str1 = str2 |
字符串相同 |
str1 != str2 |
字符串不同 |
-n str |
字符串长度不为0 |
-z str |
字符串长度为0 |
注意:=
,!=
前后都要有空格。
-e file |
file存在 |
-d file |
file是文件夹 |
-f file |
file存在,且是一个文件 |
-s file |
file存在,且size大于0 |
-r file |
file存在,且有可读权限 |
-w file |
file存在,且有可写权限 |
-x file |
file存在,且有可执行权限 |
-O file |
file存在,且当前用户为其所有者 |
-G file |
file存在,且与当前用户的所属组相同 |
file1 -nt file2 |
file1的修改时间晚于file2 |
file1 -ot file2 |
file1的修改时间早于file2 |
EXPRESSION1 -a EXPRESSION2 |
逻辑与 |
EXPRESSION1 -o EXPRESSION2 |
逻辑或 |
! EXPRESSION |
逻辑非 |
在命令行下逻辑与、逻辑或的常用形式为:
$ COMMAND1 && COMMAND2
$ COMMAND1 || COMMAND2
注意:&&
相当于”if…then…“,||
相当于“if not…then…”,都用于连接两个命令。上面的-a
和-o
用于连接两个测试条件,因此,实际使用时语法是有区别的。
可以看到&&
和||
可实现简单的分支流程功能,更复杂的流程控制则需要下面的“流程控制语句”。
[TOP]
if COMMAND1
then
commands1
elif COMMAND2
then
commands2
else
commands3
fi
if
和elif
后可以是条件判断,也可以是一个命令,这个命令返回0时,就运行then
之后相应的命令。
case var in
pattern1)
commands1;;
pattern2)
commands2;;
*)
default commands;;
esac
case
的pattern
可以匹配整型、字符型常量表达式,也可以匹配字符串,并且支持通配符。
for VAR in LIST
do
commands
done
VAR
是一个循环变量,依次取出LIST
中的值,执行commands
;LIST可以是”1 2 3 4 5”,也可以是“{1..5}”,还可以是“{0..10..2}”,表示“0 2 4 6 8 10”,当然也可以是”$(seq 1 2 20)
“。
$ for FILENAME in file?; do mv $FILENAME $FILENAME~; done
这是把file0、file1、file2…重命名为file0、file1、file2…,可以看到LIST
支持通配符。
for ((EXP1; EXP2; EXP3))
do
commands
done
这种格式类似于c语言,如((i=1; i<=5; i++))
,甚至可以用(( ; ; ))
表示无限循环。
until COMMAND
commands
done
while COMMAND
do
commands
done
while可连接到管道:
ls *.mp3 |
while read line
do
newname="[uuspider]$line"
mv $line $newname
done
或使用重定向:
while read line
do
newname="[uuspider]$line"
mv $line $newname
done < <(ls *.mp3)
break |
跳出循环 |
continue |
跳过本次循环 |
[TOP]
$0 |
shell或shell脚本的名字 |
$1、$2...${10}... |
位置参数,大于9时使用{} |
$# |
位置参数的个数 |
$@ |
所有位置参数,以列表形式输出$1 ,$2 … |
$* |
所有位置参数,整体作为单个字符串 |
$? |
上条命令的exit status |
$$ |
当前shell的进程编号 |
位置参数可以使用shift命令左移,如shift 3表示原来的$4现在变成$1,原来的$5现在变成$2…,原来的$1、$2、$3丢弃,$0不移动。不带参数的shift命令相当于shift 1。
[TOP]
$ array=(11 22 33 44 55)
查看数组长度:
$ echo ${#array[@]}
读取:
$ echo ${array[0]}
11
$ echo ${array[@]}
11 22 33 44 55
$ echo ${array[*]}
11 22 33 44 55
赋值:
$ array[0]=00
$ array[5]=11
如果某一项不存在,赋值时会自动添加新的数组元素。
删除:
$ unset array[1]
$ unset array
截取:
$ echo ${array[@]:0:3}
$ newarray=(${array[@]:1:4})
替换:
$ array=(11 22 33 44 55)
$ echo ${array[@]/33/00}
11 22 00 44 55
$ echo ${array[@]}
11 22 33 44 55
[TOP]
$ read
从标准输入读取输入,并赋值给内置变量REPLY。
$ read VAR
从标准输入读取输入并赋值给VAR。
$ read VAR1 VAR2 VAR3
从标准输入读取,第一个字符串赋值给VAR1,第二个字符串赋值给VAR2,其余字符串赋值给VAR3,字符串之间以空格或换行为界。
$ read -p "plese type something: " VAR
输入提示,并将输入赋值给VAR。
$ read -r VAR
输入时可使用反斜杠换行。
$ read -t 10
指定输入等待时间为10秒。
$ read -d ":" VAR
指定定界符为”:”,输入”:”时结束输入。
$ read -s VAR
输入时不显示输入内容。
$ read -p "input 3 letters: " -n 3 VAR
将输入的前3个字符赋值给VAR。
$ read -a array
将输入存储为数组array[@]。
$ read -dq -p "Input some words end with q: " VAR
这行代码表示以“q”为定界符,当输入q时退出输入模式。
[TOP]
函数定义:
function FUN() {
...
}
注意:左花括号与函数体之间必须有空格或换行,函数体中最后一条命令与右花括号写在同一行时,末尾必须有;
。
函数调用:
FUN
函数只有调用时候才会执行,shell脚本中的函数必须先定义再调用。注意:函数调用时,只写函数名称,不写括号。
函数返回值:
return 返回值
函数可以用return
命令返回脚本,后面跟一个数字则表示函数的Exit Status。
[TOP]
$ sh -x ./script.sh
跟踪脚本的执行信息,将执行的每一条命令和结果依次打印出来。
-n |
检查脚本中的语法错误 |
-v |
执行脚本,同时打印到标准错误输出 |
-x |
跟踪执行信息 |
脚本中可以使用set
启用或禁用上述调试参数,如:
#! /bin/sh
if [ -z "$1" ]; then
set -x
echo "ERROR: Insufficient Args."
exit 1
set +x
fi
[TOP]
通过curl
、grep
、sed
、awk
,shell可以实现简单的爬虫功能,使用python,可以实现更复杂的爬虫功能。