Linux Shell 脚本攻略
第一章 小试牛刀
1.1 Shell发展的时间线
早期计算机没有操作系统,也无图形化界面。
20世纪60年代,支持交互式界面
贝尔实验室,开发交互式用户界面,使得通过文本文件去执行程序,而非一堆命令。这些文件就是shell脚本,这带来了效率的巨大提升。
早期Unix只支持一种交互式 shell 【sh】
1989年,推出了一种全新的 shell 【bash】
随着Linux的发展,bash 逐渐成为标准shell
1.2 终端中的显示输出
界面介绍:
jacky@jacky-virtual-machine:~$
形式为:username@hostname$
$ 表示普通该用户,# 表示管理员用户root
shell 脚本
打印
echo Hello worldecho "Hello world ;world" printf "%-5s %-10s %-4s\n" No Name Markprintf "%-5s %-10s %-4.2f\n" 1 Sarath 80.3456printf "%-5s %-10s %-4.2f\n" 2 James 90.9989printf "%-5s %-10s %-4.2f\n" 3 Jeff 77.564echo -e "1\t2\t3" count=5 fruit=apple echo "We have $count ${fruit} (s)"
输出:
Hello world ------------------------------- Hello world ;world ------------------------------- No Name Mark 1 Sarath 80.35 2 James 91.00 3 Jeff 77.56 -------------------------------- 1 2 3 -------------------------------- We have 5 apple(s)
彩色打印:
echo -e "\e[1;31m This is red text \e[0m"
文字:重置=0,黑色=30,红色31,绿色=32,黄色=33,蓝色=34,洋红=35,青色=36,白色=37。
背景:重置=0,黑色=40,红色=41,绿色=42,黄色=43,蓝色=44,洋红=45,青色=46,白色=47。
环境变量
env $ pgrep gedit cat /prop/$PID /environ | tr '\0' '\n' var=1234567890 echo ${#var} echo $SHELL echo $0 echo $UID
export 命令生命了将由子进程所继承的一个或多个变量,这些变量被导出后,当前shell脚本所执行的任何应用程序都会获得这个变量。
1.5 Shell 进行数学运算
反引号的作用:存储命令
# 存储命令 cmd_output=`ls | cat -n` echo $cmd_output
在执行一条命令时,会先将其中的``中的语句当作命令执行一遍,再将结果加入到原命令中重新执行,例如:
date=`date -d '1 day ago' "+%Y-%m-%d" ` echo $date date=$(date -d '1 day ago' "+%Y-%m-%d" ) echo $date for path in `find $HADOOP_HOME -name "*.jar" `do export HADOOP_CLASSPATH=$HADOOP_CLASSPATH :$path done
整数运算
使用let
、(())
和[]
作为基本操作
no1=4; no2=5; let result=no1+no2echo $result let no+=6let no1++result=$[ no1 + no2 ] result=`expr 3 + 4` result=$(expr $no1 +5)
浮点数
echo "4 * 0.56" | bcresult=`echo "$no * 1.5" | bc` echo $result echo "scale=2;22/7" | bcno=100 echo "obase=2;$no " | bc echo "obase=10;$no " | bc echo "sqrt(100)" | bcecho "10^10" | bc
1.6 重定向与追加模式
echo "This is a sample text 1" > temp.txtecho "This is a sample text 1" > temp.txtls + 2 > out.txt 0 -- stdin (标准输入) 1 -- stdout(标准输出) 2-- stderr(标准错误)
1.7 数组与关联数组
Bash支持普通数组和关联数组。普通数组以整数
作为索引,后者使用字符串
作为索引。
普通数组
array_var=(test1 test2 test3 test4) array_var[0]="test1" array_var[1]="test2" array_var[2]="test3" array_var[3]="test4" echo ${array_var[0]} index=3 echo ${array_var[$index]} echo ${array_var[*]} echo ${array_var[@]} echo ${#array_var[*]}
关联数组
declare -A ass_arrayass_array=([index1]=val1 [index2]=val2) ass_array[index1]=val1 ass_array[index2]=val2 echo "${ass_array[index1]} " echo ${!ass_array[*]}
注:如果没有声明,则默认是数值索引数组。
1.8 alias
定义别名
alias install='sudo apt-get install' alias
alias是暂时的,一旦关闭终端,别名就会失效,若要永久使用可以把定义语句写入~/.bashrc
文件中。每当一个新的交互式shell进程生成时,都会执行~/.bashrc
文件。
echo 'alias new_command="command sequence"' >> ~./bashrc'
创建别名时,如果已经有同名的别名存在,那么原有的别名设置将被新的设置取代。
1.12 函数和参数
定义函数
function fname(){ statements; } fname() { echo $1 , $2 ; echo "$@ " ; echo "$*" ; return 0 ; } fname () { statement; }fname a b
读取外部输入:
输入参数
说明
$0
脚本的名称
$1 ,$2 ,$n
第n个参数
“$@”
被扩展成"$1" , “$2” , “$3”
“$*”
被扩展乘"$1c$2c$3"
$?
返回命令返回值
建议使用$@
,可以一个一个输出
递归函数
函数在编写的过程中可以调用自己,如下:
F () { echo $1 ; F hello; sleep 1 ; }
导出函数
$function getIP () { ifconfig $1 | grep 'inet' ; }$echo "getIP ens33" >test.sh (base) jacky@jacky-virtual-machine:~/桌面$ bash test.sh test.sh: 行 1: getIP: 未找到命令 export -f getIP(base) jacky@jacky-virtual-machine:~/桌面$ bash test.sh inet 地址:192.168.6.129 广播:192.168.6.255 掩码:255.255.255.0 inet6 地址: fe80::d74:deb0:c82e:1f79/64 Scope:Link
向命令传递参数
#! /bin/bash for i in `seq 1 $# `do echo $i is $1 shift done (base) jacky@jacky-virtual-machine:~/桌面$ bash test.sh a b c 1 is a 2 is b 3 is c
shift
命令将$1
参数一次向左移动一个位置,让脚本使用$1
访问每一个参数。
1.17 比较与测试
条件语句
if condition;then commands; fi if condition;then commands; else if condition; then commands; else commands; if
if 和 else 语句能够嵌套使用。if的条件判断可能导致代码非常长,可以通过逻辑运算符将它变得简洁一些,如下:
[ condition ] && action [ condition ] | | action
算法比较
[ $var -eq 0 ] or [ $var -ne 0 ] -gt : 大于(greater than) -lt : 小于(less than) -ge : 大于等于 -le : 小于等于 -a : 逻辑与操作符 -0 : 逻辑或操作符 [ $var 1 -ne 0 -a $var2 -gt 2 ]
文件系统相关测试
[ -f $file_var ]: 是否是一个正常的文件路径或者是文件名 [ -x $var ]: 文件是否可执行 [ -d $var ]: 是否是目录 [ -e $var ]: 是否存在文件 [ -c $var ]: 是否包含字符设备文件 [ -b $var ]: 是否包含块设备文件的路径 [ -w $var ]: 文件是否可写 [ -r $var ]: 文件是否可读 [ -L $var ]: 是否包含符号链接
例子:
fpath="/etc/passwd" if [ -e $fpath ] ; then echo File exists ; else echo Does not exits; fi
字符串比较
[[ $str1 == $str2 ]] [[ $str1 != $str2 ]] [[ -z $str1 ]] [[ -n $str1 ]]
利用&&
和||
能够组合条件:
if [[ $str1 == $str2 ]] && [[ $str1 == $str2 ]] ;then commands; fi