/etc/passwd里面保存了每个用户的shell设置
#:表示注释
#!表示该脚本使用后面指定的解释器解释执行(必须第一行)
实际上shell会fork一个子进程并调用Exec执行脚本,
实际上就是exec把进程中的原来程序段替换成现在新的程序段,
我们也可以在c语言代码中利用system()函数执行
shell命令执行
(pwd;ls -l)
pwd && ls -l
pwd || ls -l
shell 变量有全大写字母加下划线组成,有两种类型:
环境变量 本地变量
环境变量 :printenv
本地变量:只存在于当前shell进程,用set命令可以显
示当前shell进程中定义的所有变量(本地变量和环境变量)
和函数
shell脚本的调试方法
shell提供了 一些用于调试的选项
-n 读一遍脚本中的命令但不执行,用于检查脚本中的
语法错误
-v 一边执行脚本,一遍2将执行过的脚本命令打印到标准错误输出
-x 提供跟踪执行信息,将执行的每一条命令和结果一次打印出来
sh -x ./test.sh
shell脚本命令
bash的内部命令与外部命令
exit :终止当前的shell命令
export:设置一个环境变量,
当前shell的所有子进程都可以访问这个
环境变量
kill: 终止某个进程的执行
命令通配符
*:匹配任何字符和字符串,包括空字符串
?: 匹配任意一个字符。例如 ?abc 匹配任何一abc结尾或以任意
一个字符开头
[...]匹配括号里列出的任何单字符 比如 abc[def],可以匹配一abc
开头,以def中任意一个字符结尾的字符串
使用命令的历史记录
history 命令可以显示出命令的记录列表
history [n]
参数n是一个可选的整数。当没有参数时,会列出以前执行过的所有
命令,有参数n时,会列出最后执行的n个命令
history 5
这个命令显示最后执行的5个命令操作列表
命令的别名
给命令去个别名来代替命令的使用
alias list='ls -l' 定义一个文件列表的别名
如果想取消别名
unalias list 取消别名
环境变量
环境变量是在一个用户的所有进程中都可以访问的变量。系统
中常常使用环境变量来存储常用的信息
环境变量查看 export
环境变量访问 echo $SSH_ASKPASS
环境变量定义 export xx=1234
在系统配置文件中定义环境变量
环境变量的系统配置文件是/etc/profile
gedit /etc/profile
位置变量
位置变量指的是shell程序在运行时传入的参数。
程序中可以用变量的形式
来调用这些参数。这些参数存放到1-9的9个变量名中,
被称为位置变量,
同普通变量一样,位置变量用$前缀加这个数字表示
$1,$2.....$9 脚本程序的参数
$* 一个全体参数组成的清单,这是一个单独
的变量,使用环境变量IFS中的第一个字
符分隔开
$@ “$*”一种,它不使用IFS环境变量
数**算
算术运算
+:两个变量相加
-:两个变量相减
*:两个变量相乘
/:两个变量相除
**:两个变量的幂运算
%:取模运算
+=:加等于
-=:减等于
/=:除等于
%=:取模等于
shell中有三中方法可以更改运算顺序
1.用expr改变运算的顺序。可以用echo `expr 1 + 2`来输出1+2的结果
用expr表示后面的表达式为一个数**算,需要注意的是` 并不是
一个但引号,而是tab键上面的那个符号
2.用let指示数**算。可以先将运算的结果赋值个变量b,
运算命令是
b=let 1+2 ,然后用 echo $b来输出b的值,
如果没有let 则会输出
1+2
3.用$[]表示数**算,将一个数**算写到$[]符号的中括号中,
中括号中的内容将先进行数**算,例如命令 echo $[1+2]
echo 命令的输入输出
echo $a 输出变量a的值
echo $a > filename 输出变量a的值到文件filename 中
echo $a >> filename 将变量a的值追加到文件filename 中
echo输出的内容可以有下面的格式控制字符
\c 末尾加上\c 表示这一行输出完毕后不换行
\t 输出一个跳格,相当于按下“tab”键
\n 输出一个换行
需要注意的是,如果在输出特殊的字符,必须加-e选项,否则输出
的结果中会直接输出字符,加-n选项可以禁止echo输出后的换行
echo "hello beijing " hello beijing
echo "hello \nbeijing" hello beijing
echo -e "hello \nbeijing
hello
beijing
echo lizhanglin lizhanglin
echo li zhanglin 错误的输出,将不会有结果
echo "li zhanglin" li zhanglin
name="lizhanglin"
echo $name lizhanglin
echo "$name" lizhanglin
echo '$name' $name
echo \$name $name
a="asd'fgh'"
echo $a asd'fgh'
read age 读入变量值
20
echo $age 20
read命令读取命令信息
read命令可以从键盘或文件中读入信息,并赋给一个变量。
read读取信息的各种方法如下:
1.如果只读入一个变量,会把键盘上输入的信息赋值个这个变量。
2.如果输入多个变量,用空格键将输入的变量隔开。如果输入变量
的个数多与需要读取变量的个数,将会把剩余的变量赋值个最后一
个变量
3.在读取语句后面添加 < filename,表示从文件中读取数据,并赋值
给变量
read a lizhanglin a=lizhanglin
read a b c li zhang lin a=li b=zhang c=lin
read a b li zhang lin a=li b=zhang lin
vim a.txt li zhanglin
read a b < a.txt a=li b=zhanglin
文件重定向
文件重定向指的是:在执行命令时指定命令的输入,输出和错误
的输出和输入方式。例如可以命令的结果输出到一个文件中
0:标准输入 1:标准输出 2:错误输出
command > filename 把标准输出重定向到一个文件中
command >> filename 把标准输出以追加的方式重定向到一个文件中
command 1 > filename 把标准输出重定向到一个文件中
command > filename 2 >&1 把标准输出和错误输出一起重定向到
一个文件中
command 2 > filename 把标准输出的错误重定向到一个文件中
command 2 >> filename 把标准输出以追加的方式到一个文件中
command >> filename 2 > &1
把标准输出和错误追加到同一个文件中
command < filename > filename2 把command命令以filename输入,
并输出到文件filename2中
command < filename 把command 命令以filename文件作为标准输入
反引号 ``
反引号用于执行引号中的系统命令,然后将命令的结果返回
这个返回的结果可以赋值给一个变量
echo `date` 12月 10 15:06:08 CST 2007
a=`ls`
echo $a 将输出本目录下的文件清单
测试语句
对变量的大小,字符串,文件属性等内容内容进行判断
test命令可以用于字符串,数字,文件状态等内容的测试
文件状态测试
文件状态测试指的是对文件的权限,有无,属性,类型等内容进行判断
与其他语言不同的是。test命令的测试结果,返回0时表示测试成功
返回1 时表示测试失败
-d 测试文件是否是目录文件
-s 测试文件是否非空
-f 测试文件是否是正规文件
-w 测试文件是否可写
-L 测试文件是否是符号连接
-u 测试文件是否有suid位设置
-x 测试文件是否可执行
-r 测试文件是否可读
test -d /windows 测试文件/window是否是一个目录
输出结果 $?用于保存上一个命令的结果
echo $?
输出的结果1 表明/window不是一个目录
数字测试
数字测试指的是比较两个数值的大小或相等关系
1.test命令 test firstnumber 数值比较 secondnumber
2.用中括号代替test命令。需要注意的是 [ 后面一定要有一个空格
[ firstnumber 数值比较 secondnumber ]
-eq 两个数是否相等
-ne 两个数是否不相等
-le 第一个数是否小于或等于第二个数
-ge 第一个数是否大于或等于第二个数
-gt 第一个数是否大于第二个数
-lt 第一个数是否小于第二个数
如:
test 3 -lt 5 echo $? 0
[ 3 -lt 5 ]
字符串测试
字符串测试指的是比较两个字符串是否相等,或者判断一个字符串
是否为空。判断常用来测试用户输入是否符合程序的要求
字符串测试有下面4种常用的方法
test 字符串 比较符 字符串
test 字符串1 比较符 字符串2
[ 字符串 比较符 字符串 ]
[ 字符串1 比较符 字符串2 ]
字符串比较有如下所示的4种
=测试两个字符串是否相等
!=测试两个字符串是否不相等
-z:测试字符串是空字符串
-n:测试字符串是非空字符串
逻辑测试
逻辑测试指的是将多个条件进行逻辑运算
-a 逻辑与
-o 逻辑或
!: 逻辑否
[ -w a.txt -a -r b.txt ]
流程控制结构
所谓的流程控制指的是使用逻辑判断,针对判断的结果
执行不同的语句或不同的程序部分
条件判断
if语句
1. if 条件
then 命令
fi
2. if 条件
then 命令1
else 命令2
fi
3. if 条件1
then 命令1
elif 条件2
then 命令2
else 命令3
fi
4. if 条件1;then 命令1
elif 条件2;then 命令2
else 命令3
fi
5.case 语句
case结构比我们前面见过的其他语句都稍微复杂些,语法如下
case variable in
pattern ( statements;;
pattern ( statements;;
esac
case语句确实能够使我们通过一种比较深奥的机制把某个变量的内
容与
与多个摸版进行匹配,在根据成功匹配的摸版决定应该执行哪部分
代码
请注意每个摸版行都是以双引号(“;;”)结尾的。前后摸版之
间可以
有任意多余语句,因此这个双分号实际起到了分隔符的作用,
它标志着
前一个语句的结束和后一个,摸版的开始
如:
read timeofday
case “$timeofday” in
y ) echo "goodmoring";;
Y ) echo "goodmoring";;
n ) echo "goodafternoon";;
N ) echo "goodafternoon";;
* ) echo "goodday";;
esac
*是通配符,可以匹配任何一个输入的字符,最后用到*,是为了
对任何一个输入字符,都有一个处理。
case 是按照顺序,从上到下去匹配执行,没有最优匹配,最容易
匹配的放到最上面。
如:
read timeofday
case "$timeofday" in
yes | YES | y | Y ( echo "goodmoring";;
N | n ( echo "goodafternoon";;
* ( echo "goodday";;
esac
for语句
1.for 变量名 in 列表
do
命令1
命令2
done
2.当for语句省略后边的in关键字时,将接受输入时的参数作为循环
变量集
如:
for str
do
echo $str
done
在终端输入下面的命令
./test.sh a b c d e f
程序会依次列出所输入的参数
a
b
c
d
e
f
2.for 嵌套循环
for i in 1 2 3 4 5
do
for j in 1 2 3 4 5
do
done
done
until 语句
until 循环用于执行一个循环体,直至条件为真时停止
until 条件
do
命令1
done
如:
sum=0
i=1
until [ $i -gt 100 ]
do
sum=$[$sum+$i]
i=$[$i+1]
done
echo $sum
shell函数
在shell里允许定义函数,如果读者需要编写比较大型的脚本程序,
就会想到利用它们来构造自己的代码
在shell里定义一个函数的办法很简单,写出它的名字,然后是一对空
括号“()”,再把有关的语句放在一对花括号“{}”里
function_name()
{
statements
}
如:
writestring()
{
echo "lizhanglin"
}
echo "function start"
writestring
echo "function end"
在调用函数之前必须要先定义,否则出错
函数里面的变量叫局部变量,如果全句变量与局部变量同名后
则局部变量会覆盖全局变量,所以局部变量声明
local variable;
如:
samplevar="global var"
writestr()
{
local samplevar="local var"
echo "writestr is executing"
echo $samplevar
}
echo "script is executing"
echo $samplevar
writestr
echo "scriot is ending"
echo $samplevar
exit 0
如果在函数中没有用return返回一个值,那么返回的就是函数执行的最后
一句状态码值
yes_or_no()
{
echo "is it your name yes or no$*?"
while true
do
echo "enter yes or no"
read x
case "$x" in
y | yes ) return 0;;
n | no ) return 1;;
* ) echo "answer yes or no?";;
esac
done
}
echo "orgion you name$1" //$1 运行文件时输入的参数
if yes_or_no "$1" //传递参数给函数yes_or_no
then
echo "nice $1,nice name"
else
echo "never mind"
fi
exit 0
函数的参数
function getname()
{
_NAME=$1
_AGE=$2
echo $_NAME
echo $_AGE
}
function main()
{
read name age
echo "start test function"
getname $name $age
echo $?
}
main
# Clear
exit 0
函数返回值
function getsum()
{
_DATA=$1;
sum=0
while [ $_DATA -ge 1 ]
do
sum=$[$sum+$_DATA]
_DATA=$[$_DATA-1]
done
echo $sum
}
function main()
{
read data
resu=`getsum $data`
echo $resu
}
main
exit 0
递归函数应用
function factorial()
{
if [ $1 -eq 1 ]
then
echo 1
else
local temp=$[$1-1]
local result=`factorial $temp`
echo $[$result*$1]
fi
}
read -p "enter value:" value
result=`factorial $value`
echo "the factorial of $value is $result"
数组用法
arr=(123 34 3 5)
echo $arr // 默认获取第一个元素
$ echo ${arr[1]} // 通过下标访问
$ echo ${arr[@]} // 访问整个数组 ,@或者* 获取整个数组
$ echo ${#arr[@]} // 获取数组的长度(最大下标) ,#获取长度 数组中是最后一个下标
$ echo ${#arr[3]} // 获取字符串长度
$ echo ${arr[@]:1:2} // 切片方式获取一部分数组内容
$ echo ${arr[@]:2} // 从第二个元素开始
$ echo ${arr[@]::2} // 到第二个元素
允许把变量当成数组来操作,即使这个变量没有明确地被声明为数组. 1 string=abcABC123ABCabc
echo ${string[@]}
echo ${string[*]}
echo ${string[0]}
echo ${string[1]}
echo ${#string[@]}
数组中只有一个元素. 且是这个字符串本身
shell
数组操作
myarray=(1 2 3 4 5)
echo "The original array is: ${myarray[*]}"可以
打印数组中的每一项,但是在函数中就不能只能打印出
第一个值,如果非要在 函数中也能解析数组,则必须把
每个值作为参数传给函数,然后在把所有参数组成一个数组
如a6.sh例子
function testit()
{
echo "the parameters are $@"
thisarray=$1;
echo "the received array is ${thisarray[*]}"
}
myarray=(1 2 3 4 5)
echo "the original array is :${myarray[*]}"
testit $myarray
function test10()
{
local newarray
newarray=(`echo "$@"`)
echo "the new array value is:${newarray[*]}"
}
myarray=(1 2 3 4 5)
echo "the original array is ${myarray[*]}"
test10 ${myarray[*]}
function addarray()
{
local sum=0
local newarray
newarray=(`echo "$@"`)
for value in ${newarray[*]}
do
sum=$[ $sum + $value ]
done
echo $sum
}
myarray=(1 2 3 4 5)
echo "the original array is :${myarray[*]}"
arg1=`echo ${myarray[*]}`
result='addarray $arg1'
echo "the result is ${result[*]}"
function arraydir()
{
local origarray
local newarray
local elements
local i
origarray=(`echo "$@"`)
newarray=(`echo "$@"`)
elements=$[$#-1]
for ((i=0;i<=$elements;i++))
{
newarray[$i]=$[${origarray[$i]}*2]
}
echo ${newarray[*]}
}
myarray=(1 2 3 4 5)
echo "the original array is: ${myarray[*]}"
arg1=`echo ${myarray[*]}`
result=(`arraydir $arg1`)
echo "the new array is: ${result[*]}"
命令
在shell脚本程序的内部我们可以执行两大类命令普通与内建
命令。内建命令是在shell内部实现,内部命令执行效率高些
break命令
从封闭的for while until循环里中途退出。break后面可以
接一个参数n 表示退出第n个循环,不提倡这么使用
如:
rm -rf fred*
echo > fred1
echo > fred2
echo > fred3
mkdir fred4
echo > fred5
for file in fred*
do
if [ -d "$file" ];then
break;
fi
done
echo "first directory is $file"
exit 0
":"冒号命令
冒号命令是一个空命令。它偶尔会被用来简化逻辑条件,相当于tue
的 一个假名,它是内建的 所以要比用true效率高些
":"还被用在对变量进行条件化设置的情况比如
:${var:=value}
如:
rm -rf fred
if [ -f fred ];then
:
else
echo "the fred is not exsit"
fi
exit 0
continue命令
continue 类似于c语言中的 同名词,这个命令让for while until
循环跳出到下一个循环继续执行,循环变量取循环清单里的下
一个值
如:
rm -rf fred*
echo > fred1
echo > fred2
echo > fred3
mkdir fred4
echo > fred5
for file in fred*
do
if [ -d $file ];then
echo $file is directory
continue
fi
echo file is $file
done
rm -rf fred*
exit 0
eval命令
eval命令对参数进行求值操作
如:
exit命令
exit命令的作用是使脚本程序退出"n"结束运行
在shell脚本程序设计实践中退出码
"0"表示成功
"1"-"125"之间的 数字是留给脚本程序用的错误代码
"126" 文件不是可执行
"127" 命令未找到
"128及以上" 引发的一个信号
$(command)
$(command)在脚本中执行其它命令
如:
echo the current path is $pwd ---错误 没有输出
echo the current path is $(pwd) ---正确 输出当前路径
echo the man is $(who)
cd及cd目录管理系统
shell函数讲解
$n $1 表示第一个参数,$2 表示第二个参数 ...
$# 命令行参数的个数
$0 当前程序的名称
$? 前一个命令或函数的返回码(只能是0-255之间的一个值)
$* 以"参数1" "参数2" ... 形式保存所有参数
$@ 以"参数1 参数2 ... " 形式保存所有参数
$$ 本程序的(进程ID号)PID
$! 上一个命令的PID
正则表达式:
grep:打印包含模式的所有行
模式正则表达式
*:包含一个或多个字符
.:只包含一个字符
[]:匹配[]里面的字符,
可以是单个字符也可
以是字符序列
?:单个字符
^:匹配行首
$:匹配行尾
\{2\}:出现的次数
\{2,\}:至少出现的次数
\{2,5\}:出现的次数在一定的范围
^$:空行
^.$:只包含一个字符的行
[^a-zA-Z] [^0-9]
[0-9]\{4\}xx[0-9]\{4\}
awk:提取每行的信息(分为域字段)
awk '{print $0}' test.txt
awk '{print $1,$1}' text.txt
awk 'BEGIN {print "name belt\n------
"} {print $1"\t"$4}' test.txt
awk条件操作符:
< <= == != > >= ~(匹配正则表达式) !~(不匹配正则表达式)
awk条件语句例子
awk '{ print }' /etc/pawasswd
awk '{ print $0 }' /etc/passwd
awk '{ print "" }' /etc/passwd
awk '{ print "hiya" }' /etc/passwd
awk -F ":" '{ print $1 }' /etc/passwd
awk -F":" '{ print $1 $3 }' /etc/passwd
awk -F":" '{ print $1 " " $3 }' /etc/passwd
awk -F":" '{ print "username: " $1 "\t\tuid:" $3" }' /etc/passwd
awk '{if($4~/brown/) print $0}' test.txt
awk '$0 ~ /brown/' test.txt
awk '{if($3~/48/) print $0}' test.txt
awk '$3=="48" {print $0}' test.txt
awk '$0 !~/brown/' test.txt
awk '{if($4!~/brown/) print $0}' test.txt
awk '$4 !="brown" {print $0}' test.txt
awk 'if($6<$7) print $0 "$1 try better at the next comp"'
awk '{if($7<$7) print $1}' test.txt
wak '{if($6>$7) print $1}' test.txt
awk '/[gG]reen/' test.txt
awk '$1 ~/^...a/' test.txt
awk '$0~/(yellow|brown)/' test.txt
awk '/48/' test.txt
awk '/^48/' test.txt
awk '{if($1=="aaa" && $4=="yellow") print $0}' test.txt
awk '{if($1=="aaa" || $4=="yellow") print $0}' test.txt
ls -l | awk '/^[^d]/ {print $9"\t"$5} {tot+=$5} END {print "total KB:"tot}'
awk内置变量:
ARGC:命令行参数个数
ARGV:命令行参数排列
ENVIRON:支持队列中系统环境变量的使用
FILENAME:awk浏览的文件名
FNR:浏览文件的记录数
FS:设置输入域分隔符,等价于命令行-F选项
NF:浏览记录的域个数
NR:已读的记录数
OFS:输出域分隔符
ORS:输出记录分隔符
RS:控制记录分隔符
awk '{print NF,NR,$0} END{print FILENAME}' grade.txt
awk '{if(NR>0 && $4~/Brown/)print $0}' grade.txt
awk内置函数
gsub(r,s):在整个$0中用s替代r
gsub(r,s,t):在整个t中用s替代r
index(s,t):返回s中字符串t的第一位置
length(s):返回s长度
match(s,r):测试s是否包含匹配r的字符串
split(s,a,fs):在fs上将s分成序列a
sprint(fmt,exp):返回经fmt格式化后的exp
sub(r,s):用$0中最左边最长的子串代替s
substr(s,p):返回字符串s中从p开始的后缀部分
substr(s,p,n):返回字符串s从p开始长度为n的后缀部分
awk 'gsub(/4842/,4899) {print $0}' grade.txt
awk 'BEGIN {print index("Bunny","ny")}' grade.txt
awk '$1=="J.Troll" {print length($1)" " $1}' grade.txt
awk 'BEGIN {print match("ANCD",/d/)}';
awk 'BEGIN {print match("ANCD",/c/)}';
awk 'BEGIN {print split("123#454#raeqw",myarray,"#")}'
sed用法:
sed 'Command' filename(s) 只显示结果而不修改文件。
1、sed '2,5d' file 显示文件file,除去2-5行,但行数超过文件实际行数时不会报错。
sed '/10[1-4]/d' file 显示文件file,除去包含101-104的行。
sed '2,$d' file 显示文件,只显示第一行。sed '2,$!d' file则只显示除第一行外的其它行。
sed '/^ *$/d file 删除文件中的空行。
2、sed -n '/10[1-4]/p' file 只显示文件file中包含101-104的行。(-n和p必须同时使用,否则只有p时显示全部文件并多显示一次找到的行)
sed -n '5p' file 只显示文件的第5行
3、sed 's/moding/moden/g' file 将moding替换为moden
4、sed -n 's/^west/north/p' file 将west开头的行替换为north并显示出来。
5、sed 's/[0-9][0-9][0-9]$/&.5/' file将file文件中以3个数字结尾的行替换为原数字加".5",&代表搜索到的字符串。
6、sed 's/\(mod\)ing/\1en/g file 将mod做为模式1封装在括号里,然后替换。
sed 's/...$//' file 删除每一行的最后三个字符。
sed 's/^...//' file 删除每一行的头三个字符。
7、sed 's#moding#moden#g' file 将moding替换为moden,s后面的#代表搜索串和替换串之间的分界符。
8、sed -n '/101/,/105/p' file 显示从101的匹配行到105的匹配行。如果只找到101的匹配行,则从101的匹配行到文件末。
sed -n '2,/999/p' file 显示从第2行到匹配行。
9、sed '/101/,/105/s/$/ 20050119/' file将从101的匹配行到105的匹配行的行末增加" 20050119"内容。
10、sed -e '1,3d' -e 's/moding/moden/g' file 先删除文件的1-3行,再进行替换。
sed -e '/^#/!d' file 显示文件以#开头的行。
11、sed '/101/r newfile' file 在每个匹配行增加文件newfile的内容
sed '/101/w newfile' file 把匹配行写入newfile。
12、sed '/101/a\
>###' file 在匹配行后增加一新行。
sed '/101/i\
>###' file 在匹配行前增加一新行。
sed '/101/c\
>###' file 用新行替换匹配行。
13、sed 'y/abcd/ABCD/' file 将a、b、c、d分别替换为ABCD。
14、sed '5q' file 显示到第5行时退出。
15、sed '/101/{ n; s/moding/moden/g; }' file 在文件中找到匹配行的后一行(n)再进行替换。
sed '/101/{ s/moding/moden/g; q; }' file 在文件中找到第一个匹配行后进行替换后再退出。
16、sed -e '/101/{ h; d; }' -e '/104/{ G; }' file 在文件中找到与101匹配行后先存在一个缓存中,再放在与104匹配行后。
sed -e '/101/{ h; d; }' -e '/104/{ g; }' file 在文件中找到与101匹配行后先存在一个缓存中,再替代104的匹配行。
sed -e '/101/h' -e '$G' file 将最后一个匹配行放在文件末。
sed -e '/101/h' -e '$g' file 将最后一个匹配行替换文件末行。
sed -e '/101/h' -e '/104/x' file 在文件中找到与101匹配行后先存在一个缓存中,再与104的匹配行进行互换。