回顾了一些细节
shell 的通配符扩展
*
?
[]
[^xxxx]
{aaa,bbb}
子进程
more `grep -l POSIX *`
more $(grep -l POSIX *)
shell 变量的一些特性
赋值直接用变量名,获取内容需要加$
salutation=Hello
echo $salutation
读取输入
read salutation
关于shell 中的引号
#!/bin/bash
myvar="Hi there"
echo $myvar
echo "$myvar"
echo '$myvar'
echo $myvar
shell 中的预定义变量
环境变量的概念:
程序执行时,一些变量会根据环境设置中的值来进行初始化
$HOME
$PATH
$PS1
$PS2
$IFS 输入域分隔符,shell读取输入时分割单词的字符
$0 shell 脚本的名字
$# 传给脚本的参数个数
$$ shell脚本的进程号
$1 $2 第几个参数
$* 所有参数
shell 的条件判断
test 和 []
if test -f fred.c
then
…
fi
if [ -f fred.c ]
then
…
fi
test 可以使用的三类条件
1 字符串比较
string1 = string2
string1 != string2
-n string 字符串不为空则为真
-z string 字符串为空则为真
2 算术比较
expr1 -eq expr2
expr1 -ne expr2
expr1 -gt expr2
expr1 -ge expr2
expr1 -lt expr2
expr1 -le expr2
! expr 表达式为假则为真
3 文件测试
-d file 文件是目录
-e file 如果文件存在
-f file 如果是普通文件
-g file 如果set-group-id 被设置
-r file 如果文件可读
-s file 未果文件大小不为0
-u file 如果set-user-id 被设置
-w file 如果文件可写
-x file 如果文件可执行
通过read获取的值,引用时最好用双引号引起来,这样的话,直接回车变量就是空字符串
输出不换行
有些系统不支持用echo -e
bash 可以用 echo -n
最好用printf
shell 中的控制结构
1 if
echo "yes or no"
read timeofday
if [ "$timeofday" = "yes" ]; then
echo "good"
else
echo "wrong"
fi
exit 0
2 elif
echo "yes or no"
read timeofday
if [ "$timeofday" = "yes" ]
then
echo "Good morning"
elif [ "$timeofday" = "no" ]; then
echo "good"
else
echo "sorry"
exit 1
fi
exit 0
3 for
for foo in bar fud 43
do
echo $foo
done
exit 0
for file in $(ls f*.sh); do
cat $file
done
exit 0
4 while
echo "Enter password"
read trythis
while [ "$trythis" != "secret" ]; do
echo "Sorry, try again"
read trythis
done
exit 0
5 until 反复执行,知道为真
监控某个用户登陆
until who | grep "$1" > /dev/null
do
sleep 60
done
echo -e 'a'
echo " *** $1 has logged in *** "
exit 0
6 case 语句
基础用法
echo "yes or no"
read timeofday
case "$timeofday" in
yes) echo "Good morning";;
no ) echo "good afternoon";;
y ) echo "good morning";;
n ) echo "good afternoon";;
* ) echo "sorry";;
esac
exit 0
合并匹配模式
echo "yes or no"
read timeofday
case "$timeofday" in
yes | y | Yes | YES ) echo "morning";;
n* | N* ) echo "afternoon";;
* ) echo "sorry";;
esac
exit 0
执行多条语句
echo "yes or no"
read timeofday
case "$timeofday" in
yes | Y | Yes | YES )
echo "morning"
echo "up"
;;
[nN]* )
echo "good afternoon"
;;
*)
echo "sorry"
echo no"
exit 1
;;
esac
exit 0
7 and 和 or
短路逻辑
and &&
touch file_one
rm -f file_two
if [ -f file_one ] && echo "hello" && [ -f file_two ] && echo " there"
then
echo "in if"
else
echo "in else"
fi
exit 0
or ||
8 语句块
在只允许单个语句的地方,比如(and or 列表) ,可以用花括号构造一个语句块
shell 中的函数
foo() {
echo "function"
}
echo "start"
foo
echo "end"
exit 0
函数中的局部变量
shell 中的函数默认会使用全局变量
sample_text="global variable"
foo() {
local sample_text="local variable"
echo "function foo executing"
echo $sample_text
}
echo "start"
echo $sample_text
foo
echo "end"
echo $sample_text
exit 0
函数参数传递与返回值
#!/bin/bash
yes_or_no() {
echo "Is your name $* ?"
while true
do
echo -n "Enter yes or no: "
read x
case "$x" in
y | yes ) return 0;;
n | no ) return 1;;
* ) echo "answer yes or no"
esca
done
}
echo "Original paramers are $*"
if yes_or_no "$1"
then
echo "Hi $1, nice name"
else
echo "Never mind"
fi
exit 0
shell 提供的命令
1 break
2 : 等价于true
3 continue
4 . 在当前shell中执行命令
. ./shell_script
source ./shell_script
5 echo
建议在现代shell中用printf
6 eval
foo=10
x=foo
eval y='$'$x
echo $y
# 结果为10
7 exec
exec典型用法时将当前shell替换为一个不同程序,脚本后面的代码不会执行
exec wall "Thanks for all the fish"
另一种用法是修改当前文件描述符
exec 3< afile
打开文件描述符3,从afile读取数据
8 exit
9 export
export命令将作为它参数的变量导出到子shell中
10 expr
expr 将它的参数当作数学表达式运算
x=10
x=`expr $x + 1`
expr 支持的运算符
expr1 | expr2 如果expr1非零,则等于exp1,否则等于expr2
expr1 & expr2 只要有一个表达式为零,则等于零,否则等于expr1
expr1 = expr2
expr1 > expr2 >= < <= != + - * / %
expr 常被替换为 $((…))
11 printf
printf "%s
" hello
printf "%s %d %s" "Hi There" 15 people
12 return
使函数返回,如果函数没有return,则返回值是最后一条命令的退出码
13 set
set 用来为shell设置参数变量
14 shift命令
shift把所有参数变量左移一个位置,使$2变成 $1,以此类推
15 trap
trap用于指定在接收到信号后要采取的行动
trap -l 查看信号编号和关联的名称
trap command signal
重置某个信号的处理方式,command -
忽略某个信号 command 设置为空字符串’'
#!/bin/bash
trap "rm -f /tmp/my_tmp_file_$$" INT
echo creating file /tmp/my_tmp_file_$$
date > /tmp/my_tmp_file_$$
echo "press interrupt ( C-c ) to interrupt …."
while [ -f /tmp/my_tmp_file_$$ ]; do
echo File exists
sleep 1
done
echo The file no longer exists
trap "" INT
echo creating file /tmp/my_tmp_file_$$
date > /tmp/my_tmp_file_$$
echo "press interrupt (C-c) to interrupt ….."
while [ -f /tmp/my_tmp_file_$$ ]; do
echo File exists
sleep 1
done
echo we never get here
exit 0
16 unset
unset 用来从环境中删除变量或函数,不能删除shell本身定义的只读变量
17 find
find [path] [option] [tests] [actions]
基本用法
find / -name test -print
-print 是默认action
不搜索挂载的其他文件系统的目录
find / -mount -name test -print
在当前目录下搜索比文件while2新的文件
find . -newer while2 -type f -print
组合测试
find . ( -name "_*" -or -newer while2 ) -type f -print
执行一条命令,动作必须用;字符对结束
find . -newer while2 -type f -exec ls -l {} ;
18 grep
grep [options] PATTERN [FILES]
如果没有提供文件名,grep会使用标准输入
grep in words.txt
grep -c in words.txt words2.txt 输出匹配的统计
grep -c -v in words.txt words2.txt -v 取反
grep 中的正则表达式
常用的特殊字符
^
$
.
[] 里面是范围[a-z] 范围前加^表示反向字符
在方括号内可以使用的一些有用的特殊匹配模式,比如[[:alnum:]]
[:alnum:]
[:alpha:]
[:ascii:]
[:blank:] 空格或制表符
[:cntrl:]
[:digit:]
[:graph:]
[:graph:]
[:lower:]
[:print:]
[:punct:]
[:space:] 空白字符,包括垂直制表符
[:upper:]
[:xdigit:] 十六进制数字
如果指定了-E可以用扩展匹配,但是需要加
?
*
+
{n}
{n,}
{n,m}
查找以字母e结尾的行
grep e$ words2.txt
查找以字母a结尾的单词
grep a[[:blank:]] words2.txt
查找以Th开头的,由三个字母组成的单词
grep Th.[[:space:]] words2.txt
查找长度为10,都由小写字母组成的单词
grep -E [a-z]{10} words2.txt
shell 中获得命令执行结果
whoisthere=$(who)
echo $whoisthere
如果需要把命令输出转换为参数,并作为另一个程序的参数,可以用xargs
expr 的新扩展 $((..))
x=0
while [ "$x" -ne 10 ]; do
echo $x
x=$(($x+1))
done
exit 0
参数扩展
基本用法
for i in 1 2
do
my_secret_process ${i}_tmp
done
参数扩展
${param:-default} 如果param为空,把它设置为default的值
${#param} 给出param的长度
${param%word} 从param尾部开始删除与word匹配的最小部分,返回剩余部分
${param%%word} 尾部 最长
${param#word} 头部 最小
${param##word} 头部 最长
unset foo
echo ${foo:-bar} # bar
foo=fud
echo ${foo:-bar} # fud
foo=/usr/bin/X11/startx
echo ${foo#*/} # usr/bin/X11/startx
echo ${foo##*/} # startx
bar=/usr/local/etc/local/networks
echo ${bar%local*} # /usr/local/etc
echo ${bar%%local*} # /usr/
批量转换GIF为JPEG
for image in *.gif
do
cjpeg $image > ${image%%gif}jpg
done
here 文档
ed a_text_file <<!FunkyStuff!
3
d
.,$s/is/was/
w
q
!FunkyStuff!
exit 0
shell 脚本调试
1 只检查语法错误,不执行命令
sh -n <script>
set -o noexec
set -n
2 执行命令前回显它们
sh -v <script>
set -o verbose
set -v
3 执行完命令后回显它们
sh -x <script>
set -o xtrace
set -x
4 如果使用了未定义的变量,就给出错误消息
sh -u <script>
set -o nounset
set -u
通过捕获EXIT信号,查看脚本退出时的状态
trap "echo Exiting: critical variable=$critical_variable" EXIT