Shell 脚本(shell script),是一种为 shell 编写的脚本程序。
业界所说的 shell 通常都是指 shell 脚本,但读者朋友要知道,shell 和 shell script 是两个不同的概念。
由于习惯的原因,简洁起见,本文出现的 “shell编程” 都是指 shell 脚本编程,不是指开发 shell 自身。
单引 双引 反引用[] [[]]
将命令的输出读入一个变量中,可以将它放入双引号中,即可保留空格和换行符(\n)
out=$(cat text.txt)
输出1 2 3
out="$(cat text.txt)"
输出:
1
2
3
逻辑运算符:
-gt 大于
-lt 小于
-ge 大于等于
-le 小于等于
逻辑与-a
[ $var1 -eq 0 -a $var2 -gt 2 ]
逻辑或
[ $var1 -eq 0 -o $var2 -gt 2 ]
[ condition ] && action 等价于if…fi
if [ “$LOOK_OUT” -gt “85” ]
if [ -e /home/slynux ]; then
…
fi
-----------------[[]]一般用于字符串比较
if [[ -n $str1 ]] && [[ -z $str2 ]] ;
then
commands;
fi
========================
1、字符串判断
str1 = str2 当两个串有相同内容、长度时为真
str1 != str2 当串str1和str2不等时为真
-n str1 当串的长度大于0时为真(串非空) if [[ -n $1 ]]
-z str1 当串的长度为0时为真(空串)
str1 当串str1为非空时为真
2、数字的判断
int1 -eq int2 两数相等为真
int1 -ne int2 两数不等为真
int1 -gt int2 int1大于int2为真
int1 -ge int2 int1大于等于int2为真
int1 -lt int2 int1小于int2为真
int1 -le int2 int1小于等于int2为真
3 目录文件的判断(if [ ])
-r file 用户可读为真
-w file 用户可写为真
-x file 用户可执行为真
-f file 文件为正规文件为真
-d file 文件为目录为真
-c file 文件为字符特殊文件为真
-b file 文件为块特殊文件为真
-s file 文件大小非0时为真
-t file 当文件描述符(默认为1)指定的设备为终端时为真
3、复杂逻辑判断
-a 与
-o 或
! 非
下面是一些使用实例:
#!/bin/sh
myPath="/var/log/httpd/"
myFile="/var /log/httpd/access.log"
#这里的-x 参数判断 m y P a t h 是 否 存 在 并 且 是 否 具 有 可 执 行 权 限 i f [ ! − x " myPath是否存在并且是否具有可执行权限 if [ ! -x " myPath是否存在并且是否具有可执行权限if[!−x"myPath"]; then
mkdir “$myPath”
fi
#这里的-d 参数判断 m y P a t h 是 否 存 在 i f [ ! − d " myPath是否存在 if [ ! -d " myPath是否存在if[!−d"myPath"]; then
mkdir “$myPath”
fi
#这里的-f参数判断 m y F i l e 是 否 存 在 i f [ ! − f " myFile是否存在 if [ ! -f " myFile是否存在if[!−f"myFile" ]; then
touch “$myFile”
fi
#其他参数还有-n,-n是判断一个变量是否是否有值
if [ ! -n “ m y V a r " ] ; t h e n e c h o " myVar" ]; then echo " myVar"];thenecho"myVar is empty”
exit 0
fi
#两个变量判断是否相等
if [ “ v a r 1 " = = " var1" == " var1"=="var2” ]; then
echo ‘$var1 eq v a r 2 ′ e l s e e c h o ′ var2' else echo ' var2′elseecho′var1 not eq $var2’
fi
-----------------获取名称.扩展名
file_jpg=“sample.jpg”
name=${file_jpg%.*}
输出sample
file_jpg=“sample.jpg”
extension=${file_jpg#*.}
输出jpg
------------------ time 计算命令执行时间
time command
--------------- 重定向
0 stdin标准输入
1 stdout标准输出
2 stderr标准错误
文件打开模式:
等同于1> 截断模式
等同于1>> 追加模式
<用于从文件中读取至stdin 只读模式
ls + 2> out.txt
stdout不会有任何输出,因为错误已经重定向到out.txt中了
可以将stderr单独重定向到一个文件,将stdout重定向到另一个文件:
cmd 2>stderr.txt 1>stdout.txt
将stderr转换成stdout,使得stderr和stdout都被重定向到同一个文件:
cmd 2>&1 output.txt
或者
cmd &> output.txt
将stderr输出丢弃
some_command 2> /dev/null
将文件重定向到命令
cmd < file
向log文件中写入头部数据
#!/bin/bash
cat LOG FILE HEADER this is a test log file EOF -----------------------/dev/null 2>&1 */1 * * * * root /usr/local/php/bin/php /var/w.php > /dev/null 2>&1 crontab内容:50 18 5-30 * * /script/myscript.sh 1> /dev/null 2>&1 换句话说,就是不显示该程序执行过程中的任何信息 cmd >a 2>a 和 cmd >a 2>&1 为什么不同? ----------------- 算数运算 let expr let 可以直接执行基本的算数操作 no1=4 no2=5 let result=no1+no2 echo $result let no1++ let no1+=6 操作符[] ,expr 和let命令类似 result=$[ no1 + no2 ] result=$[ $no1 + $no2 ] result= result=$(expr $no1 + 5) ---------------- 浮点运算 bc #echo “4 * 0.56” | bc 2.24 -----------------获得字符串长度 var=123456 echo ${#var} -----------------环境变量$PATH和export echo $PATH PATH通常定义在/etc/environment或/etc/profile或~/.bashrc中 export命令用来设置环境变量; 添加新的路径: export PATH="$PATH:/home/user/bin" 或者 PATH="$PATH:/home/user/bin" export PATH 其它环境变量:HOME,PWD,USER,UID,SHELL 查看进程相关的环境变量: cat /proc/$PID/environ ----------------- printf 格式化输出 printf “%-5s %-10s %-4s\n” No Name Mark printf “%-5s %-10s %-4.2f\n” 1 James 91.32 输出为: No Name Mark 1 James 91.32 %-5s 指明了一个格式为左对齐且宽度为5的字符串替代(- 表示左对齐) -4.2f 表示对浮点数的处理格式 -------------- 读取命令返回值$? cmd; echo $?; -------------------------shell 调试 #!/bin/bash -xv 不用任何其他选项就可以启用调试功能了 sh -n sh16.sh 不执行script,仅查询语法 sh -x sh16.sh 将script执行过程全部列出来 需要给变量赋值时,可以这么写: a=“hello world” //if 注意空格 a=$1 if [[ $a -eq 2 ]] ;then echo “1” else echo “2” fi if [[ $a = gjslint ]] ;then echo “1” exit 0 else echo “2” fi exit 0 ===================== 调用php的sh #!/bin/bash if [[ $0 = /* ]] then curfile="$0" else curfile=" P W D / PWD/ PWD/{0#./}" fi #得到curfile 为/usr/local/shell/automation/autoupdate_host.sh php_path= #得到php_path为/usr/local/shell/automation PHP="/usr/local/php/bin/php -q " PROGRAM="${php_path}/clear_his.php" #echo $PHP $PROGRAM & $PHP $PROGRAM & ====================== [和[[有什么不同 $ type [ 也就是说[处理里面的字串是当作参数来处理的,而[[对待其中的字串是当作表达式来处理的 表达式中不会有wordsplitting 或者glob expansion,而参数处理会有 $ ls ]$ (foo=“file 1”;[ -f KaTeX parse error: Expected 'EOF', got '&' at position 6: foo ]&̲&echo "foo is a file") # 这里file 1被分成2个word,所以出错 再来看看glob expansion $ touch '’ 参数传递中<和>会被解析成重定向符号,所以必须转义掉 $ ([ “s” < “l” ]&&echo yes) #错误使用 $ ([ “s” > “l” ] &&echo yes) #正确使用 $ ([[ “s” > “l” ]] &&echo yes) #而在表达式中比较符号不会被当作重定向符号 参数传递中小括号会被分割成token,而在表达式中则会被解析成运算顺序 $ ([ “s” > “l” -a ( file “l” > “a” -o “l” > “p” ) ]&&echo yes) #(和)必须被转义,以避免参数解析中的不正确分词 $ ([ “s” > “l” -a “l”“a"−o"l”“p” ] &&echo yes) $ ([[ “s” > “l” && ( “l” > “a” || “l” > “p” ) ]] &&echo yes; ) #而表达式则不需要考虑这个 ================ shell判断文件是否存在 shell判断文件,目录是否存在或者具有权限 myPath="/var/log/httpd/" if [ ! -x “ m y P a t h " ] ; t h e n m k d i r " myPath"]; then mkdir " myPath"];thenmkdir"myPath” if [ ! -d “ m y P a t h " ] ; t h e n m k d i r " myPath"]; then mkdir " myPath"];thenmkdir"myPath” if [ ! -f “ m y F i l e " ] ; t h e n t o u c h " myFile" ]; then touch " myFile"];thentouch"myFile” if [ ! -n “ m y V a r " ] ; t h e n e c h o " myVar" ]; then echo " myVar"];thenecho"myVar is empty” if [ “ v a r 1 " = " var1" = " var1"="var2” ]; then -f 和-e的区别 -a file exists. ==================bash中的特殊符号 ? 万用字符,代表一个字母 | 分隔两个管线命令的界定; $ 亦即是变量之前需要加的变量取代值 & 将指令变成背景下工作 ! 逻辑运算意义上的『非』 not 的意思! / 路径分隔的符号 , >> 输出导向,分别是『取代』与『累加』 ’ 单引号,不具有变量置换的功能 " 具有变量置换的功能! ( ) 在中间为子 shell 的起始与结束 [ ] 在中间为字符的组合 { } 在中间为命令区块的组合! exit 1:退出整个程序 --------------------dirname dirname /home/bin/abc ------------------------- 循环读取每行 : -----------------------整数比较 -eq 等于,如:if [ “ a " − e q " a" -eq " a"−eq"b” ] if [ $counter -gt 1 ]; then … fi < 小于(需要双括号),如:((“ a " < " a" < " a"<"b”)) 大于(需要双括号),如:((“ a " > " a" > " a">"b”)) ---------------------------字符串比较 大于,在ASCII字母顺序下.如: awk ‘{print $2}’ class.txt | grep ‘1’ > res iptables 配置文件目录 /etc/sysconfig/iptables 1.别名 alias,存放位置 $HOME/.bashrc 环境变量:系统变量,用于所有用户,只有环境变量才能用于所有的子进程中,本地变量不可以。 变量替换:用变量的值替换变量的名 --------------------位置变量:$0 $1…$9 向系统命令传递参数 标准变量:bash默认的,可以在/etc/profile中定义 ----------------------------------------------------------特殊变量 $$脚本运行的当前id号 $!后台运行的最后一个进程id号 ./tesh.sh a b c declare :设置或显示变量 -f只显示函数名 read:可以从键盘或文件的某一行文本中读入信息,并将其赋给一个变量。 read -t 5 variable 5秒钟超时 read -s -p "Please enter your Password: " pass -s charaters are not echoed. 字符不回显示。指输入之后,不在回显 0-9. ↩︎
其中 1> /dev/null 2>&1是什么意思??
dev/null 为系统垃圾箱
&为后台运行
但是 myscript 后面的1 和 /null后面的2 还有 &后面的1是什么意思?
1代表标准输出,2代表错误信息输出.
1>/dev/null 就是指将标准输出定向到空设备,
2>&1,的意思是将错误输出定向到和1一样的输出设备,也同样是空.
cmd >a 2>a :stdout和stderr都直接送往文件 a ,a文件会被打开两遍 ,由此导致stdout和stderr互相覆盖。
cmd >a 2>&1 :stdout直接送往文件a ,stderr是继承了FD1的管道之后,再被送往文件a 。a文件只被打开一遍,就是FD1将其打开
他们的不同点在于:
cmd >a 2>a 相当于使用了FD1、FD2两个互相竞争使用文件 a 的管道;
而cmd >a 2>&1 只使用了一个管道FD1, 但已经包括了stdout和stderr。
从IO效率上来讲,cmd >a 2>&1的效率更高。expr 3 + 4
变量名=值
要取用一个变量的值,只需在变量名前面加一个$
echo “A is:” $adirname $curfile
[ is a shell builtin
$ type [[
[[ is a shell keyword
那么当作参数和表达式有什么不同呢?
file file 1 #注意是2个文件(file 和file 1)
$ (foo=“file 1”;[[ -f KaTeX parse error: Expected 'EOF', got '&' at position 7: foo ]]&̲&echo "foo is a file")
file 1 is a file
bash: [: file: binary operator expected
$ (foo="";[ -f KaTeX parse error: Expected 'EOF', got '&' at position 6: foo ]&̲&echo "foo is a file") #为什么显示too many arguments,因为 被扩展为所有目录下的文件
bash: [: too many arguments
$ (foo="";[[ -f KaTeX parse error: Expected 'EOF', got '&' at position 7: foo ]]&̲&echo "foo is a file") # *被当成普通字符了
bash: l: No such file or directory
yes
yes
bash: syntax error near unexpected token `(’
yes
yes
#!/bin/sh
myFile="/var /log/httpd/access.log"这里的-x 参数判断$myPath是否存在并且是否具有可执行权限
fi这里的-d 参数判断$myPath是否存在
fi这里的-f参数判断$myFile是否存在
fi其他参数还有-n,-n是判断一个变量是否是否有值
exit 0
fi两个变量判断是否相等
echo ‘$var1 eq v a r 2 ′ e l s e e c h o ′ var2' else echo ' var2′elseecho′var1 not eq $var2’
fi
Conditional Logic on Files
-b file exists and is a block special file.
-c file exists and is a character special file.
-d file exists and is a directory.
-e file exists (just the same as -a).
-f file exists and is a regular file.
-g file exists and has its setgid(2) bit set.
-G file exists and has the same group ID as this process.
-k file exists and has its sticky bit set.
-L file exists and is a symbolic link.
-n string length is not zero.
-o Named option is set on.
-O file exists and is owned by the user ID of this process.
-p file exists and is a first in, first out (FIFO) special file or named pipe.
-r file exists and is readable by the current process.
-s file exists and has a size greater than zero.
-S file exists and is a socket.
-t file descriptor number fildes is open and associated with aterminal device.
-u file exists and has its setuid(2) bit set.
-w file exists and is writable by the current process.
-x file exists and is executable by the current process.
-z string length is zero.
两个『 ` 』中间为可以先执行的指令!
得到/home/bin
all_corp=sql.txt
cat $all_corp | while read line
do
echo $line
done
-ne 不等于,如:if [ “ a " − n e " a" -ne " a"−ne"b” ]
-gt 大于,如:if [ “ a " − g t " a" -gt " a"−gt"b” ]
-ge 大于等于,如:if [ “ a " − g e " a" -ge " a"−ge"b” ]
-lt 小于,如:if [ “ a " − l t " a" -lt " a"−lt"b” ]
-le 小于等于,如:if [ “ a " − l e " a" -le " a"−le"b” ]
<= 小于等于(需要双括号),如:((“ a " < = " a" <= " a"<="b”))
= 大于等于(需要双括号),如:((“ a " > = " a" >= " a">="b”))
= 等于,如:if [ “ a " = " a" = " a"="b” ]
== 等于,如:if [ “ a " = = " a" == " a"=="b” ],与=等价
注意:==的功能在[[]]和[]中的行为是不同的,如下:
1 [[ KaTeX parse error: Expected 'EOF', got '#' at position 12: a == z* ]] #̲ 如果a以"z"开头(模式匹配 )那么将为true
2 [ KaTeX parse error: Expected 'EOF', got '#' at position 13: a == "z*" ] #̲ 如果a等于z*(字符匹配 ),那么结果为true
3
4 [ KaTeX parse error: Expected 'EOF', got '#' at position 11: a == z* ] #̲ File globbing …a" == “z*” ] # 如果 a 等 于 z ∗ ( 字 符 匹 配 ) , 那 么 结 果 为 t r u e 一 点 解 释 , 关 于 F i l e g l o b b i n g 是 一 种 关 于 文 件 的 速 记 法 , 比 如 " ∗ . c " 就 是 , 再 如 也 是 . 但 是 f i l e g l o b b i n g 并 不 是 严 格 的 正 则 表 达 式 , 虽 然 绝 大 多 数 情 况 下 结 构 比 较 像 . ! = 不 等 于 , 如 : i f [ " a等于z*(字符匹配),那么结果为true 一点解释,关于File globbing是一种关于文件的速记法,比如"*.c"就是,再如~也是. 但是file globbing并不是严格的正则表达式,虽然绝大多数情况下结构比较像. != 不等于,如:if [ " a等于z∗(字符匹配),那么结果为true一点解释,关于Fileglobbing是一种关于文件的速记法,比如"∗.c"就是,再如 也是.但是fileglobbing并不是严格的正则表达式,虽然绝大多数情况下结构比较像.!=不等于,如:if["a" != “ b " ] 这 个 操 作 符 将 在 [ [ ] ] 结 构 中 使 用 模 式 匹 配 . < 小 于 , 在 A S C I I 字 母 顺 序 下 . 如 : i f [ [ " b" ] 这个操作符将在[[]]结构中使用模式匹配. < 小于,在ASCII字母顺序下.如: if [[ " b"]这个操作符将在[[]]结构中使用模式匹配.<小于,在ASCII字母顺序下.如:if[["a” < “ b " ] ] i f [ " b" ]] if [ " b"]]if["a” < “$b” ]
注意:在[]结构中"<"需要被转义.
if [[ “ a " > " a" > " a">"b” ]]
if [ “ a " " a" \> " a""b” ]
注意:在[]结构中">“需要被转义.
具体参考Example 26-11来查看这个操作符应用的例子.
-z 字符串为"null”.就是长度为0.
-n 字符串不为"null"
注意:
使用-n在[]结构中测试必须要用"“把变量引起来.使用一个未被”“的字符串来使用! -z
或者就是未用”“引用的字符串本身,放到[]结构中。虽然一般情况下可
以工作,但这是不安全的.习惯于使用”"来测试字符串是一种好习惯.
alias ll=‘ls -lh’
2.print=helloworld echo ${print}
3.变量:内存中一块存储单元
本地变量:登陆登出生命周期内有效,只限制于本用户
变量名=变量值
set 查看
LOCAL=“TEST”
echo $LOCAL
设置变量名为只读,不能在更改,同是也不能在恢复:readonly 变量名,不能删除。
存放于/etc/profile .bash_profile
export 变量名=变量值
env或者export查看
unset 变量名 删除
print=helloworld
echo ${print}
echo f i l e 1 + {file1}+ file1+{file2}
$0:脚本的名字
$1:脚本的第一变量
$2:脚本的第二变量
向脚本中使用位置参数:./test.sh a b c
find /root/ -name $1 -print
./test.sh aa
EXINIT
HOME
IFS:设置分隔符,默认为空格 IFS=":"SHE
LOGNAME
MAIL 默认邮箱位置
MAILPATH多个邮箱时可以设置
TERM 显示终端类型
PS1 当前shell目录格式PS1=“WANGJIAN:”
ps2 >
pwd显示当前路径 SHELL 显示当前shell
MANPATH TERMINFO
$# 变量的个数 $* 显示脚本全部参数(参数列表)
$?显示前一个命令的运行状态
#!/bin/bash
echo “tesh.sh”
echo “this is first variable locate:$1”
echo “this is second variable locate:$2”
echo “this is third variable locate: 3 " s h i f t e c h o " c o u n t : 3" shift echo "count: 3"shiftecho"count:#”
echo “all list: ∗ " e c h o " p i d : *" echo "pid: ∗"echo"pid: " e c h o " s t a t u s : " echo "status: "echo"status:?”
export:创建环境变量 -p显示所有环境变量
readonly:设置只读变量,不能修改删除
unset:取消变量的定义。-f 删除只读变量
shift:输入的位置变量改变位置 shift 表位置上移一个位置,shift 2 表上移动两个位置
双引号"":引用字符或字符串除$ \ 单引号\'\':直接引用为字符或字符串 反引号``: 作为系统命令执行 echo
echo wangjian` wangjian
反斜杆:转义特殊字符(KaTeX parse error: Expected 'EOF', got '&' at position 26: …算符:~取反 << >>移位 &̲与(同1为1,否0) |或(有…[]:表示对其中的表达式求值 echo $[2+8] echo $[3&4] $[]等价于(())
[base#n] n(base>n)表示基数从2到36的任何基数 echo [10#8+1] 结果为9
let a+=3 a=a+3
表达式优先级别[] *= || && | ^ & ==
shell 的输入与输出
echo
-e 解析转义字符 echo -e “this is a bag \n\n\n”
-n 回车不换行,默认换行 echo -n “this is a cat”
转义字符(\c回车不换行 \f禁止 \t跳格相当tab \n回车换行)
read varible1 varible2
如果只指定了一个变量,那么read将会把所有的输入赋给改变量,直至遇到文件结束或回车。如果多个变量,就依次赋给。shell用空格作为变量之间的分隔符。
echo -n “first name:”
read firstname
echo -n “last name:”
read lastname
echo -e "your first name :KaTeX parse error: Undefined control sequence: \n at position 12: {firstname}\̲n̲" echo -e "your…{lastname}\n "
read -p "Please enter your Username: " user -p prompt 提示语
[root@ceshiji ~]#Please enter your Username: