这是自己在从学习shell到实际编一些小脚本的过程中,总结的一些shell知识,这些知识可能都能在其他地方看到,只是我把它们整合了一下,其中包含shell一些基本但又极其重要的部分,希望分享给大家作为编写shell时的手边备忘。 由于这些是从学习shell开始到现在,偶尔逐步追加的一些points,不连续,缺乏连贯性和逻辑性,限于本人level,难免其中有些小bug,若发现,还望指出。
shell三种流程控制结构(判断,分支,循环)
#判断
if [condition]
then
cmd-list
elif [condition]
then
cmd-list
else
cmd-list
fi
注:elif [condition]; then 部分是可选的,是0个或多个关系:{elif [condition]; then}*
------------------------------------------------------我是分隔线------------------------------------------------
#分支
case var in
1)cmd-list;;
2)cmd-list;;
3)cmd-list;;
*)default-list;
esac
注:经常与它配套使用的还有一种类似控件选择分支的结构叫select,在此不多介绍了,常与case结合使用的一种特殊循环
------------------------------------------------------我是分隔线------------------------------------------------
#三种循环
for var in [value-list]
do
cmd-list
done
------------------------------------------------------我是分隔线------------------------------------------------
while [condition]
do
cmd-list
done
------------------------------------------------------我是分隔线------------------------------------------------
until [condition]
do
cmd-list
done
------------------------------------------------------我是分隔线------------------------------------------------
流程控制是shell编程最基本的地方,在此再贴上这几种结构的例子:
#!/bin/sh
#if.sh file
echo "Input a number:" read var
if [ -z $var ] then echo "var is empty, you input nothing" elif [ $var -le 5 ] then echo "$var low equal than 5" else echo "$var greater than 5" fi
------------------------------------------------------我是分隔线------------------------------------------------
#!/bin/sh
#case.sh file
case $# in
0) echo "No parameter.";;
1) echo "1 parameter:$1";;
2) echo "2 parameters:$1 $2";;
*) echo "More than 2 parameters:$@";;
esac
------------------------------------------------------我是分隔线------------------------------------------------
#!/bin/sh
#for.sh file
for var in A B C do echo "var is $var" done
------------------------------------------------------我是分隔线------------------------------------------------
#!/bin/sh
#while.sh file
echo "Please input sth to echo:"
while read var do echo "$var"
done
------------------------------------------------------我是分隔线------------------------------------------------
#!/bin/sh
#until.sh file
echo "Please input sth to echo:"
until read var; [ -z "$var" ] do echo "$var"; done
------------------------------------------------------我是分隔线------------------------------------------------
0.shell变量 <1>等号两边不能有空格 <2>无数据类型概念,全部变量都理解为字符型 <3>变量替换 a=2334 # 整型. let "a += 1" # 仅支持bash echo "a = $a " # a = 2335 echo # 还是整型. b=${a/23/BB} # 将"23"替换成"BB". <4>'string' 单引号 (single quote, hard quote) 被单引号用括住的内容,将被视为单一字串。在引号内的代表变数的$符号,没有作用,也就是说,他被视为一般符号处理,防止任何变量替换。 heyyou=homeecho '$heyyou' # We get $heyyou
<5>"string" 双引号 (double quote, soft quote) 被双引号用括住的内容,将被视为单一字串。它防止通配符扩展,但允许变量扩展。这点与单引数的处理方式不同。
1.函数间接引用传递,eg. Say="Hello"; Hello="World!";
echo ${Say}; echo ${!Say};
输出:HelloWorld!
2.特殊变量 <1>$*变量: 存储命令行键入的全部参数$*=$1c$2c... c is the first char of IFS, if IFS is unset, c=' ', else if IFS is null, c is null too. <2>$@变量: 命令行键入参数列表,注意与$*的区别$@="$1" "$2" ... <3>$#变量: 存储命令行键入的参数个数 <4>$?变量: 退出状态存储的变量--系统自动(foreground pipeline) <5>$-变量: current option flags <6>$$变量: 存储shell的进程ID,如果在子进程中,该变量是其父shell的进程ID <7>$!变量: 存储系统最后一个进程的id,eg. command &后台异步的进程(background & asynchronous) <8>$0变量: 存储程序名 <9>${n}变量: 当传递的参数大于9的时候,必须使用这种方式来存取第10、11、…参数 <10>$_变量:
3.关于命令的执行 三种方法执行shell脚本:
<1>重定向给sh:
$:sh < script.sh
<2>传递脚本文件给sh:
$: sh script.sh
<3>直接执行script.h:
$: chmod a+x script.sh
$: ./script.sh
前两种方法的优点是,script.sh不一定是可执行的,最后一种却需要执行权限,优点是直观。
4.管道与标准输入输出: 需要参数的命令如果不指定参数,会从标准输入中获得输入;==>管道(主要第一个程序向标准输出写入输出,第二个程序从标准输入读取输入,就可以建立管道)
5.查找并替换 sed 's/Fine/FINE/g' test.txt > temp 修改保存在临时文件 (g为全局选项,否则只替换每行的第一个单词) mv temp test.txt 更新原来文件 将test.txt 中的Fine替换为FINE。
6.从1到多个文件中搜索特定字符 grep -n 'shell' ed.cmd 从文件ed.cmd中找出shell所在的行(grep -i 参数忽略大小写 -v 不包含选项 -n 包含行数选项)
7.排序 sort 文件名 -u 去处重复行 -r 反序排序 -o 输出给同名文件 (直接保存到原文件中) +1n 跳过一个字段(空格或制表符为单词间隔) -t:以":"为跳跃间隔符 sed -n '/shell/p' ed.cmd 同结果 cat /etc/passwd | sort -t: -k3.1,3,4 -nr #逆序将用户ID排序
8.查找重复行 uniq test.txt -d 找出重复的行 -c 统计重复行的次数
9.算数扩展运算 $((算数表达式/逻辑表达式))
10.引用 单引号(hard quote):shell严格的忽略全部单引号之间的字符 双引号(soft quote):shell不忽略$、反斜杠、反引号 反斜杠:等价单引号,对一个字符有效,适用于去掉特殊意义的字符,以免被shell解析(\c与'c' 等价) 放在一行最后,可以用于忽略换行符,也就是续行
11.命令替换 $()或者反引号``引起来,在子shell中执行命令,eg. $(pwd) `pwd`
12.参数传递 从命令行接受参数,shell自动把从命令行中接受的第一个参数存放在第一个变量,第二个放第二个,…… 从变量出现的位置开始算,同名算一个 shift命令每执行一次,变量的个数($#)减一,而变量值提前一位 当只有0个参数时,执行命令会报错 shift n:执行n次shift eg. shift.sh #!/bin/sh while [ $# -ne 0 ] do echo $1 done 结果:./shift.sh file1 file2 file3 将输出file1死循环 file1 file1 file1 ...... eg. shift.sh #!/bin/sh while [ $# -ne 0 ] do echo $1 shift #add this command done 结果:./shift.sh file1 file2 file3 将依次输出参数 file1 file2 file3
13.垃圾桶 /dev/null 对于某些输出到标准输出的命令,如果不想输出,则可以重定向输出到系统垃圾桶中
14.逻辑操作符 ! 逻辑非 -a 逻辑与 -o 逻辑或
15.空命令 :
16.格式化输出 printf命令 可以格式化的显示 printf "format" arg1 arg2 … %表参数: echo自动添加换行符,printf不会 "\n"可以进行换行
17.导出变量 export variables 父shell利用导出变量,能够将值复制给子shell,对所有后续子shell有效 export -p :清单
18.exec命令 exec program :启动一个新的shell代替当前的shell,所以这个语句后面的任何命令将无效(但可以用子shell去执行$exec, 如使用括号(exec pwd))
19.( … )和{ …; }结构 ( … ) 子shell执行命令(可以没有空格,末尾可以没有分号) { …; } 当前shell执行命令(必须有空格,末尾必须有分号)
但命令串执行()和{}有区别: A,()只是对一串命令重新开一个子shell进行执行 B,{}对一串命令在当前shell执行 C,()和{}都是把一串的命令放在括号里面,并且命令之间用;号隔开 D,()最后一个命令可以不用分号 E,{}最后一个命令要用分号 F,{}的第一个命令和左括号之间必须要有一个空格 G,()里的各命令不必和括号有空格 H,()和{}中括号里面的某个命令的重定向只影响该命令,但括号外的重定向则影响到括号里的所有命令 20.深入参数 <1>参数替换 ${parameter} mv $file ${file}x :改名,给文件名增加X ${parameter:-value}:parameter 不为空,则替换值
${parameter:=value}:当parameter 不为空,不但使用value,而且赋值给parameter;不能用在位置参数上(也就是parameter不能使数字) 典型用法:测试导出变量是否设置了值,如果没有,就将它设为默认值
${parameter:?value}: 不为空替换,否则把value写入标准错误,然后退出
${parameter:+value}: 不为空替换,否则啥也不替换
<2>模式匹配
<3>set命令 设置各种shell选项,或者给位置参数$1,%2等重新赋值
<4>IFS变量
<5>readonly命令
<6>unset命令
21.函数 name () {command; … command;} 函数在定义shell中有效。 可以将一些常用的函数放在一个单独的文件中,然后通过点(.)来调用,那样,就可以在shell编程中使用。 <1>unset -f name 将函数定义去除 <2>return命令 exit会结束调用的shell,用return来结束函数运行
22.杂项 <1>eval命令 shell双次稍描命令行 <2>wait命令 wait process-id:省略进程号的话默认全部子进城 <3>trap命令 trap commands signals: 常用信号编号: 0-退出shell 1-挂起 2-中断(例如Delete、Ctrl+C键) 15-软件结束信号(默认由kill发出) <4>深入I/O <$-:关闭标准输出 >&-:关闭标准输入 <5>关于shell语句末的分号 shell中分号(;)仅起分隔语句的作用,如果一行仅有一条shell语句,则不用加分号, 但如果一行写有多条语句,则语句间要用分号隔开。比如if语句后面的then如果同if 在同一行就必须用;,eg. if [ -z $arg ]; then <6>bash中有一个特性,通过declare a定义的a为整数
23.引用回溯命令的参数!^ !$ !!:n !^: previous command's first arguments !$: previous command's last arguments !*: previous command's all arguments list !!:0 --> previous command name !!:1 --> previous command's first argument !!:n --> previous n-th argument |