1,格式
- 开头格式:#!/bin/bash
- 结尾格式:#$?
2,参数
- $# 是传给脚本的参数个数
- $0 是脚本本身的名字
- $1 是传递给该shell脚本的第一个参数
- $2 是传递给该shell脚本的第二个参数
- $@ 是传给脚本的所有参数的列表
- $* 是以一个单字符串显示所有向脚本传递的参数,与位置变量不同,参数可超过9个
- $$ 是脚本运行的当前进程ID号
- $? 是显示最后命令的退出状态,0表示没有错误,其他表示有错误
3,IFS
- IFS:为shell的特殊环境变量作为分隔符来用
#!/bin/bash IP=192.168.2.1 echo $IP IFS="." echo $IP 输出结果为: 192.168.2.1 192 168 2 1
4,echo命令
- echo:输出字符串结尾有换行符;
- echo -n “”:输出字符串去掉结尾的换行符
- echo -e “”:出现以下字符进行解释
- “\a”:警示字符;
- “\b”:退格;
- “\c”:忽略最后的换行符;
- “\f”:清屏;
- “\n”:换行;
- “\r”:回车;
- “\0ddd”: 将字符表示成1到3位的八进制数值
5,实例代码
#!/bin/bash
# 1
#单引号标记字符串
echo 'The time and date are :'
#使用命令
date
#双引号标记字符串
echo "Let's see who's logged into the system:"
#使用命令
who
#去掉末尾换行符 -n
echo -n "Time are:"
date
#2
#使用环境变量
echo "User info for userid: $USER"
echo "UID: $UID"
echo "HOME: $HOME"
#使用转义字符
echo "The cost of the item is \$15"
#用户自定义变量
days=10
guest="Katie"
echo "$guest checked in $days days ago"
#3
#反引号允许把命令输出给变量
testing='date'
echo "The date and time are:"$testing
#用反引号捕获当前日期,并用它在脚本中创建唯一的文件名,这是一种为日志文件名提取日
#期信息的常用技术;+%y%m%d格式指示date命令使用两位数来显示年,月,日
today='date +%y%m%d'
ls /usr/bin -al > log.$today
#4
#输出重定向 command > outputfile
#创建文件,重写文件内容
data > log.txt
#附加数据到现有文件
data >> log.txt
#输入重定向 command < inputfile
#wc命令计数内置输入重定向提供的数据的行,单词,字节的数目
wc < log.txt
#5
#当为一个变量指定数字时,使用美元符号和方括号($[operation])
var1 = $[1+5]
echo $var1
var2 = $[$var1 * 2]
echo $var2
#6
#浮点数解决方案,使用内置的bash计算器(成为bc)
#bash计算器实际上是一种编程语言,该语言允许在命令行中输入浮点数表达式,然后计算它们
#在脚本中使用bc:variable='echo "options; expression" | bc'
#scale:浮点数输出位数
var3 = 'echo "scale=4; 3.44/5" | bc'
echo The answer is $var3
#7
#使用内置输入重定向方法,而不使用文件重定向;内置输入重定向允许从命令行直接定向数据
#EOF文本字符串表明内置重定向数据的开始和末尾
#variable='bc << EOF
#options
#statements
#expressions
#EOF
#'
var4=10.46
var5=43.67
var6=33.2
var7=71
var8='bc << EOF
a1 = ($var4 * $var5)
b1 = ($var6 * $var7)
a1+b1
EOF
'
#8
#脚本使用if行的date命令,如果命令执行成功,echo语句将显示文本字符串
if date
then
echo "it worked"
fi
if hello
then
echo "it worked"
else
echo "it not worked"
fi
#9
#数字比较
#-eq:是否相等;-ge:大于或等于;-gt:大于;-le:小于或等于;-lt:小于;-ne:不相等
data1 = 10
data2 = 11
if [$data1 -eq $data2]
then
echo "The value are equal"
else
echo "The value are different"
fi
#字符串比较
#=:是否相同;!=:是否不同;<:是否小于;>:是否大于;
#-n str:是否大于;-z str:是否为0
testuser=rich
if [@USER != $testuser]
then
echo "This isn't $testuser"
else
echo "Welcome $testuser"
fi
#字符串大小比较需要用转义字符或者会被认为:重定向字符
str1=baseball
str2=hockey
if [$str1 \> $str2]
then
echo "$str1 is greater than $str2"
else
echo "$str1 is less than $str2"
fi
#文件比较
#-d file:是否存在并且是一个目录;-e file:是否存在;-f file:是否存在并且是一个文件
#-r :是否存在并可读;-s:是否存在并不为空;-w:是否存在并可写;-x:是否存在并可执行
#file1 -nt file2:file1是否比file2新;file1 -ot file2:file1是否比file2旧;
if [-d $HOME]
then
echo "Your HOME directory exists"
cd $HOME
ls -a
else
echo "There's a problem with your HOME directory"
fi
#10
#复合条件检查
if [-d $HOME] && [-w $/HOME/testing]
then
echo "The file exists and you can write to it"
else
echo "I can't write to the file"
fi
#11
#双圆括号:允许在比较中包含高级数学公式 ((expression))
#val++:后增量;val--:后减量;++val:前增量;--val:前减量;!:逻辑否定
#~:取反;**:取幂;<<:左移;>>:右移;&:布尔逻辑与;|:布尔逻辑或;
#&&:逻辑与;||:逻辑或
data3=10
if (($data3**2 > 90))
then
((data4=$data3**2))
echo "The square of $data3 is $data4"
fi
#12
#双方括号:[[expression]]模式匹配,可以定义与字符串值相匹配的正则表达式
if [[$USER == r*]]
then
echo "Hello $USER"
else
echo "Sorry, I don't know you"
fi
#13
#case语句
case $USER in
rich | barbara)
echo "welcom, $USER";;
testing)
echo "please enjoy your visit";;
jessica)
echo "Don't forget to log off";;
*)
echo "Sorry";;
esac
#$?
#循环的相关使用
#!/bin/bash
echo "*****************1************************"
for num in 1 2 3 4 5 6 7 8 9 10 #for循环格式
do
echo -n "num=$num; " #-n:去掉最后换行符
done
echo -e "\nnum=$num" #-e:进行转义
echo "*****************2************************"
for test in I do\`t know if this\`ll work #特别字符处理
do
echo "word:$test"
done
echo "*****************3************************"
for num in "num 1" "num 2" "num 3" "num 4" "num 5" "num 6" "num 7" "num 8" "num 9"
do #带空格字符处理
echo -n "$num; "
done
echo -e "\n$num"
echo "*****************4************************"
list="1 2 3 4 5 6 7 8 9 10" #使用变量,赋值时 “=”左右不能有空格
for num in $list
do
echo -n "num=$num; "
done
echo -e "\nnum=$num"
echo $?
echo "*****************5************************"
for num in `cat hello` #使用命令
do
echo -n "num=$num; "
done
echo -e "\nnum=$num"
echo "*****************6************************"
for file in /home/zzy/* #使用通配符读取目录
do
if [ -d "$file" ]
then
echo "Dir=$file"
elif [ -f "$file" ]
then
echo "File=$file"
fi
done
echo "*****************7************************"
for ((i=0; i<10; i++)) #C模式循环
do
echo -n "num=$i; "
done
echo -e "\nnum=$i"
echo "*****************8************************"
var1=10
while [ $var1 -gt 0 ] #while循环
do
echo -n "var=$var1; "
var1=$[$var1-1]
done
echo -e "\nvar=$var1"
echo "*****************9************************"
var1=100 #until循环
until [ $var1 -eq 0 ]
do
echo -n "var1=$var1; "
var1=$[$var1-25]
done
echo -e "\nvar1=$var1"
echo "****************10************************"
IFS_OLD=$IFS #文件数据循环
IFS=$'\n'
for entry in `cat hello`
do
echo "$entry"
done
IFS=$IFS_OLD
echo "****************11************************"
for var in 1 2 3 4 5 #退出循环
do
echo "var=$var"
if [ $var -eq 2 ]
then
break; #break n:n=1退出当前循环;n=2退出外部循环
fi
done
echo "****************12************************"
for var in 1 2 3 4 5 #结束本次循环
do
if [ $var -eq 2 ];then
continue;
fi
echo "var=$var"
done > output.txt #输出到文件
#$?
输出结果:
*****************1************************
num=1; num=2; num=3; num=4; num=5; num=6; num=7; num=8; num=9; num=10;
num=10
*****************2************************
word:I
word:do`t
word:know
word:if
word:this`ll
word:work
*****************3************************
num 1; num 2; num 3; num 4; num 5; num 6; num 7; num 8; num 9;
num 9
*****************4************************
num=1; num=2; num=3; num=4; num=5; num=6; num=7; num=8; num=9; num=10;
num=10
0
*****************5************************
cat: hello: No such file or directory
num=10
*****************6************************
*****************7************************
num=0; num=1; num=2; num=3; num=4; num=5; num=6; num=7; num=8; num=9;
num=10
*****************8************************
var=10; var=9; var=8; var=7; var=6; var=5; var=4; var=3; var=2; var=1;
var=0
*****************9************************
var1=100; var1=75; var1=50; var1=25;
var1=0
****************10************************
cat: hello: No such file or directory
****************11************************
var=1
var=2
****************12************************
#脚本参数和用户输入处理
#!/bin/bash
echo "The code name is $0" #$0 程序名称
if [ -n "$1" ];then
echo "The first para is $1" #$1 第一个参数
fi
if [ -n "$2" ];then
echo "The second para is $2" #$2 第二个参数
fi
if [ -n "$1" ] && [ -n "$2" ];then
var1=$[ $1+$2 ]
echo "The total value is $var1"
fi
if [ -n "$1" ] #判断长度是否大于0
then
echo "hello $1"
else
echo "sorry no para"
fi
echo "all para num = $#" #$# 总参数个数
echo "the last para is ${!#}" #${!#} 最后一个参数
echo "\$* all pare = $*" #$* 输出所有参数,把参数作为一个单词
echo "\$@ all_pare = $@" #$@ 输出所有参数,把参数作为一个字符串
#$*与$@的不同
coutn=1
for param in "$*"
do
echo "\$* Parameter #$count=$param"
count=$[$count+1]
done
count=1
for param in "$@"
do
echo "\$@ Parameter #$count=$param"
count=$[$count+1]
done
#运行脚本:
# ./test12 rich barbara
#输出结果:
# $* Parameter #1=rich barbara
# $@ Parameter #1=rich
# $@ Parameter #2=barbara
#使用shift命令时,默认将每一个参数变量左移一个位置,$3值移给$2,$2值移给$1,$1值被丢弃
count=1
while [ -n "$1" ]
do
echo "pare #$count = $1"
count=$[ $count + 1 ]
shift #参数左移 $1丢弃
done
#运行脚本:
# ./test12 rich barbara katie
#输出结果:
# $@ Parameter #1=rich
# $@ Parameter #2=barbara
# $@ Parameter #3=katie
#处理带参数的选项
while[-n "$1"]
do
case "$1" in
-a) echo "Found the -a option";;
-b) param = "$2"
echo "Fount the -b option, with parameter value $param"
shift 2;;
-c) echo "Found the -c option";;
--) shift
break;;
*) echo "$1 is not an option";;
esac
shift
done
#运行脚本:
# ./testing -a -b test1 -c -d
#输出结果:
# Found the -a option
# Found the -b option, with parameter value test1
#-d is not an option
#getopt命令可以接受任意形式的命令行选项和参数列表,并自动将这些选项和参数转换为
#合适的格式,命令格式:getopt options optstring parameters(optstring:选项
#字符串,定义命令行中的有效选项字母,它还定义哪些选项字母需要参数值),在选项字符
#串中列出将在脚本中用到的每个命令行选项字母,然后在每个需要参数值的选项字母后面放
#置一个冒号
getopt ab:cd -a -b test1 -cde # "ab:cd":选项字符串 b:表示b需带参数
# "-a -b test1 -cde":输入参数
# 其中-cde被分解成'-c' '-d' '-e' e:因为选项字符串中没有报错
getopt -q ab:cd -a -b test1 -cde # -q:忽略 -e 报错
getopt -q ab:cd -a -b -c meng xiang #输出结果:-a -b '-c' -- 'meng 'xinag'
#默认把'-c'作为-b的参数 用'--' 来分割额外的参数
#set命令的一个选项是双破折号,表示将命令行参数变量替换为set命令的命令行中的值
#这个技巧是:将原始脚本命令行参数送给getopt命令,然后将getopt命令的输出送给
#set命令,以便将原始命令行参数替换为通过getopt格式化过的更精细的形式
set -- `getopt -q ab:cd "$@"` #将命令行参数变量替换为set命令行命令中的值
while [ -n "$1" ] #操作参数和选项参数分离
#do #getopt:为所处理的选项和参数生成一个输出
case "$1" in
-a)
echo "Found the -a option";;
-b)
echo "Found the -b option";;
-c)
echo "Found the -c option";;
--)
shift
break;;
*)
break;;
esac
shift
done
#运行脚本:
# ./testing -a -b test1 -c -d
#输出结果:
# Found the -a option
# Found the -b option, with parameter value test1
#-d is not an option
#每调用一次getopts,它只处理在命令中监测到的参数中的一个,处理完所有参数后,以大于零的状态退出
#getopts命令的格式为:getopts optstring variable
while getopts :ab:c opt #getopts:对shell参数变量进行处理
do #在选项字符串前面加‘:’表示忽略错误
case "$opt" in #每调用一次getopts,它只处理命令中检测到灯参数中的一个,处理完所有参数后
a) echo "Found the -a option";; #以大于零的退出状态退出
b) echo "Found the -b option, with value $OPTARG";;
c) echo "Found the -c option";; #OPTIND:getopts停止处理时在shell参数列表中的位置
*) echo "Unkonwn option: $opt";; #OPTARG:包含需要参数值的选项要使用的值 此处为-b的参数
esac
done
shift $[ $OPTIND-1 ] #移除命令选项,使参数从$1开始
count=1
for para in $@
do
echo "Para #$count $para"
count=$[ $count+1 ]
done
#运行脚本:
# ./testing -ab test1 -c
#输出结果:
# Found the -a option
# Found the -b option, with parameter value test1
#Found the -c option
#read命令接受标准输入(键盘)的输入,或其他文件描述符的输入,得到输入后,read命令将数据放入
#一个标准变量中
echo -n "Enter your name:"
read name # 读取键盘命令
echo "hello $name"
read -p "Enter your age:" age # "-p"选项,允许在read命令中直接进行一行提示
echo "you live $age year"
read -p "Enter your name and age:" name age # 多个参数
echo "hello $age $name" # 如果不指定变量,变量默认存储在REPLY中
# "-t"计时选项:当计时器计时满时,返回一个非零状态
if read -t 5 -p "Please enter your name:" name
then
echo "hello $name, welcome"
else
echo "sorry too slow"
fi
read -n1 -p "Enter your choice:[Y?N]?" answer # "-n1":表示允许读取一个字符
case $answer in
Y | y) echo ""
echo "fine, OK come on";;
N | n) echo ""
echo "OK, goodbye";;
esac
read -s -p "Enter your password" pass # "-s":表示输入不进行回显
echo ""
echo "right pass"
count=1
cat hello | while read line # "读取文件":每次读取一行,当没有文件可读时,返回非零状态
do
echo "Line $count1: $line"
count=$[ $count+1]
done
#数据显示
#linux使用文件描述符:标识每个文件对象,文件描述符是一个非负整数,可以唯一地标识会话中打开的文件
#linux标准文件描述符: 0:STDDIN:标准输入;1:STDOUT:标准输出;2:STDERR:标准错误
#!/bin/bash
echo "This is error out" >&test6 #临时重定向 >&file
echo "This is normal"
#exec 1>test7 #永久重定向,下面输出到test7文件中
#echo "hello long world"
#echo "hello samll world"
#exec 0<hello #重新定向输入
#count=1
#while read line
#do
# echo "Line #$count:$line"
# count=$[ $count + 1 ]
#done
exec 3>&1 #重新定向文件描述符
exec 1>test6
echo "This should store in the output file"
exec 1>&3
echo "Now come back"
exec 6<&0 #创建输入文件描述符
exec 0<hello
count=1
while read line
do
echo "Line #$count:$line"
count=$[ $count + 1 ]
done
exec 0<&6
read -n1 -p "Are you done now:" answer
case $answer in
Y | y) echo -e "\nGood come on";;
N | n) echo -e "\nSorry GoodBye";;
*) echo -e "\nError GoodBye" ;;
esac
exec 3>test6
echo "This is a test" >&3
exec 3>&- #关闭文件描述符
#echo "This won\`t work" >&3
ls -al > /dev/null #禁止命令输出
mktemp test9.XXXXXX #创建临时文件 用此格式确保文件在目录中的唯一性
mktemp test9.XXXXXX
ls -al test9.*
rm -rf test9.*
mktemp -t test9.XXXXXX #强制在/tmp中创建文件
ls -al /tmp/test9.*
rm -rf /tmp/test9.*
mktemp -d dir.XXXXXX #创建临时目录
ls -al dir.*
rm -rf dir.*
echo "hello world 1" >&test6
echo "hello world 2" >&test6
echo "hello world 1" | tee test7 #相当于重定向,但是支持标准输出和消息同时记录
echo "hello world 2" | tee -a test7