系统管理中 bash shell 脚本常用方法总结
1. 单引号和双引号的区别
单引号与双引号的最大不同在于双引号仍然可以引用变量的内容,但单引号内仅是 普通字符 ,不会作变量的引用,直接输出字符窜。请看如下例子:
[root@linux ~]# name=HaHa [root@linux ~]# echo $name HaHa [root@linux ~]# myname="$name is wow" [root@linux ~]# echo $myname HaHa is wow [root@linux ~]# myname='$name is wow' [root@linux ~]# echo $myname $name is wow从上面例子可以看出,使用了单引号的时候,那么$name只是普通字符,直接输出而已!
2. 逐行读取文件使用for循环来读取文件 for line in `cat file.txt` do echo $line done
注意:由于使用for来读入文件里的行时,会自动把空格和换行符作为一样分隔符,如果行里有空格的时候,输出的结果会很乱,所以只适用于行连续不能有空格或者换行符的文件
使用while循环读取文件 cat file.txt |while read line do echo $line done 或者: while read line do echo $line done < file.txt
3. bash shell 脚本中常用隐含变量注意:由于使用while来读入文件里的行时,会整行读入,不会关注行的内容(空格..),所以比for读文件有更好的适用性,推荐使用while循环读取文件
注意: $? 用于检查上一个命令执行是否正确(在Linux中,命令退出状态为0表示该命令正确执行,任何非0值表示命令出错)
$$ 变量最常见的用途是用做暂存文件的名字以保证暂存文件不会重复。
$* 和 $@ 如果输出是一样的,但是在使用for循环,在使用 双引号(”")引用时 “$*” 会输出成一个元素 而 “$@” 会按照每个参数是一个元素方式输出
请看测试例子
#cat test.sh #!/bin/sh echo '"$@" output.....' for i in "$@" do echo $i done echo '"$*" output ....' for i in "$*" do echo $i done #sh test.sh a b c d "$@" output..... a b c d "$*" output .... a b c d4. 变量内容的删除与替换从输出结果可以看出 “$*” 输出是一行 而 “$@” 输出则是四行
我们在一些情况下,需要对变量中的字符窜进行查找删除或者替换,就需要使用下表列出的方法
举例如下(删除字符窜中的某个字符):
[root@linux ~]# export test_str="/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin" [root@linux ~]# echo ${test_str#/*kerberos/bin:} /usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin5. 变量条件测试赋值在某些时刻我们需要‘判断’某个变量是否存在,若变量存在则将此变量值赋值给新的变量,若变量不存在则将其他值赋值给新的变量.
举例如下:
[root@linux ~]# test_name="" [root@linux ~]# test_name=${test_name-root} [root@linux ~]# echo $test_name <== 因为 test_name 被设定为空字符窜!所以当然还是保留为空字符窜! [root@linux ~]# test_name=${test_name:-root} [root@linux ~]# echo $test_name root <== 加上‘:’后若变量内容为空或者是未设定,都能够以后面的内容替换!6. shell 中分隔符 : 变量IFS 使用基本上这种变量的测试也能够透过 shell script 内的 if…then… 来处理,不过通过上述提及的简单的方法来测试变量,是程序看起来更精简一些!
shell脚本中,如果使用for循环一个字符窜的话,默认使用空格来分割字符窜. 还有前面所提到的 使用for循环逐行读取文件内容时候,文件行中如果有空格的话输出的结果也会变乱. 这个时候 使用 IFS 变量来设置特定的字符窜分割符来,达到输出正确的目的. 默认情况下 IFS 是使用 <space><tab><newline>, 空格 \t \n 来作为默认的分割符的.
我们将前面使用for逐行读取文件的例子 改进下就可以输出正确了,请看下面
#!/bin/bash IFS_old=$IFS #将原IFS值保存,以便用完后恢复 IFS=$’\n’ #更改IFS值为$’\n’ for line in `cat file.txt` do echo $line donefile.txt 文件内容如下
[root@linux]$ cat file.txt sdfsdfsdfsdf ssssss ssssss ssssss sssss sdfsdfsdfsdfsdf执行测试程序 输出结果如下(正确输出)
[root@linux]$ sh test.sh sdfsdfsdfsdf ssssss ssssss ssssss sssss sdfsdfsdfsdfsdf如果未设置IFS变量,使用默认的IFS变量值 ,输出结果如下
[root@linux]$ sh test.sh sdfsdfsdfsdf ssssss ssssss ssssss sssss sdfsdfsdfsdfsdf从以上测试程序输出结果,可以根据自己的需求来设定 IFS变量,在举一个例子如下:
while IFS=: read userName passWord userID groupID geCos homeDir userShell do echo "$userName -> $homeDir" done < /etc/passwd7. shell 数组的使用数组赋值方式:
(1) array=(var1 var2 var3 ... varN) (2) array=([0]=var1 [1]=var2 [2]=var3 ... [n]=varN) (3) array[0]=var1 arrya[1]=var2 ... array[n]=varN计算数组元素个数或者长度:
(1) ${#array[@]} (2) ${#array[*]}了解了数组基础语法,举例说明,请看:
#!/bin/bash NAMESERVERS=("ns1.www.net." "ns2.www.net." "ns3.www.net.") # 得到数组长度 tLen=${#NAMESERVERS[@]} # 循环数组 for (( i=0; i<${tLen}; i++ )); do echo ${NAMESERVERS[$i]} done在看一个复杂一点的例子,将文件内容读取到数组中:
#!/bin/bash # 设置IFS将分割符 设置为 换行符(\n) OLDIFS=$IFS IFS=$'\n' # 读取文件内容到数组 fileArray=($(cat file.txt)) # restore it IFS=$OLDIFS tLen=${#fileArray[@]} # 循环显示文件内容 for (( i=0; i<${tLen}; i++ )); do echo "${fileArray[$i]}" done8. 逻辑判断 条件测试文件属性的判断
举例如下,测试文件是否存在:
#!/bin/bash echo "checks the existence of the messages file." echo -n "Checking..." if [ -f /var/log/messages ];then echo "/var/log/messages exists." fi echo echo "...done."字符串比较
举例如下,比较字符串来测试用户ID :
if [ "$(whoami)" != 'root' ]; then echo "You have no permission to run $0 as non-root user." exit 1; fi数值比较(整数)
举例如下:
num=`wc -l work.txt` if [ $num -gt 150 ];then echo "you've worked hard enough for today." echo fi如果要查看详细的测试操作,可以查看man手册 man test
via https://blog.163.com/cleave@126/blog/static/35476386201092014331642/?suggestedreading&wumii