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 参数判断$myPath是否存在并且是否具有可执行权限
if [ ! -x "$myPath"]; then
mkdir "$myPath"
fi
#这里的-d 参数判断$myPath是否存在
if [ ! -d "$myPath"]; then
mkdir "$myPath"
fi
#这里的-f参数判断$myFile是否存在
if [ ! -f "$myFile" ]; then
touch "$myFile"
fi
#其他参数还有-n,-n是判断一个变量是否是否有值
if [ ! -n "$myVar" ]; then
echo "$myVar is empty"
exit 0
fi
#两个变量判断是否相等
if [ "$var1" == "$var2" ]; then
echo '$var1 eq $var2'
else
echo '$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
其中 1> /dev/null 2>&1是什么意思??
dev/null 为系统垃圾箱
&为后台运行
但是 myscript 后面的1 和 /null后面的2 还有 &后面的1是什么意思?
1代表标准输出,2代表错误信息输出.
1>/dev/null 就是指将标准输出定向到空设备,
2>&1,的意思是将错误输出定向到和1一样的输出设备,也同样是空.
换句话说,就是不显示该程序执行过程中的任何信息
cmd >a 2>a 和 cmd >a 2>&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的效率更高。
----------------- 算数运算 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=`expr 3 + 4`
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 %-4sn" No Name Mark
printf "%-5s %-10s %-4.2fn" 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"
echo "A is:" $a
//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="$PWD/${0#./}"
fi
#得到curfile 为/usr/local/shell/automation/autoupdate_host.sh
php_path=`dirname $curfile`
#得到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 [
[ is a shell builtin
$ type [[
[[ is a shell keyword
也就是说[处理里面的字串是当作参数来处理的,而[[对待其中的字串是当作表达式来处理的
那么当作参数和表达式有什么不同呢?
表达式中不会有wordsplitting 或者glob expansion,而参数处理会有
$ ls
file file 1 #注意是2个文件(file 和file 1)
$ (foo="file 1";[[ -f $foo ]]&&echo "$foo is a file")
file 1 is a file
]$ (foo="file 1";[ -f $foo ]&&echo "$foo is a file") # 这里file 1被分成2个word,所以出错
bash: [: file: binary operator expected
再来看看glob expansion
$ touch '*'
$ (foo="*";[ -f $foo ]&&echo "$foo is a file") #为什么显示too many arguments,因为 *被扩展为所有目录下的文件
bash: [: too many arguments
$ (foo="*";[[ -f $foo ]]&&echo "$foo is a file") # *被当成普通字符了
* is a file
参数传递中
================ shell判断文件是否存在
shell判断文件,目录是否存在或者具有权限
#!/bin/sh
myPath="/var/log/httpd/"
myFile="/var /log/httpd/access.log"
# 这里的-x 参数判断$myPath是否存在并且是否具有可执行权限
if [ ! -x "$myPath"]; then
mkdir "$myPath"
fi
# 这里的-d 参数判断$myPath是否存在
if [ ! -d "$myPath"]; then
mkdir "$myPath"
fi
# 这里的-f参数判断$myFile是否存在
if [ ! -f "$myFile" ]; then
touch "$myFile"
fi
# 其他参数还有-n,-n是判断一个变量是否是否有值
if [ ! -n "$myVar" ]; then
echo "$myVar is empty"
exit 0
fi
# 两个变量判断是否相等
if [ "$var1" = "$var2" ]; then
echo '$var1 eq $var2'
else
echo '$var1 not eq $var2'
fi
-f 和-e的区别
Conditional Logic on Files
-a file exists.
-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.
==================bash中的特殊符号
* 万用字符,代表一个或多个字符(或数字)
? 万用字符,代表一个字母
# 批注,这个最常被使用在 script 当中,视为说明!
跳脱符号,将『特殊字符或万用字符』还原成一般字符
| 分隔两个管线命令的界定;
; 连续性命令的界定(注意!与管线命令并不相同)
~ 使用者的家目录
$ 亦即是变量之前需要加的变量取代值
& 将指令变成背景下工作
! 逻辑运算意义上的『非』 not 的意思!
/ 路径分隔的符号
>, >> 输出导向,分别是『取代』与『累加』
' 单引号,不具有变量置换的功能
" 具有变量置换的功能!
` ` 两个『 ` 』中间为可以先执行的指令!
( ) 在中间为子 shell 的起始与结束
[ ] 在中间为字符的组合
{ } 在中间为命令区块的组合!
exit 1:退出整个程序
--------------------dirname
dirname /home/bin/abc
得到/home/bin
------------------------- 循环读取每行 :
all_corp=sql.txt
cat $all_corp | while read line
do
echo $line
done
-----------------------整数比较
-eq 等于,如:if [ "$a" -eq "$b" ]
-ne 不等于,如:if [ "$a" -ne "$b" ]
-gt 大于,如:if [ "$a" -gt "$b" ]
-ge 大于等于,如:if [ "$a" -ge "$b" ]
-lt 小于,如:if [ "$a" -lt "$b" ]
-le 小于等于,如:if [ "$a" -le "$b" ]
if [ $counter -gt 1 ]; then
...
fi
< 小于(需要双括号),如:(("$a" < "$b"))
<= 小于等于(需要双括号),如:(("$a" <= "$b"))
> 大于(需要双括号),如:(("$a" > "$b"))
>= 大于等于(需要双括号),如:(("$a" >= "$b"))
---------------------------字符串比较
= 等于,如:if [ "$a" = "$b" ]
== 等于,如:if [ "$a" == "$b" ],与=等价
注意:==的功能在[[]]和[]中的行为是不同的,如下:
1 [[ $a == z* ]] # 如果$a以"z"开头(模式匹配 )那么将为true
2 [ $a == "z*" ] # 如果$a等于z*(字符匹配 ),那么结果为true
3
4 [ $a == z* ] # File globbing 和word splitting将会发生
5 [ "$a" == "z*" ] # 如果$a等于z*(字符匹配),那么结果为true
一点解释,关于File globbing是一种关于文件的速记法,比如"*.c"就是,再如~也是.
但是file globbing并不是严格的正则表达式,虽然绝大多数情况下结构比较像.
!= 不等于,如:if [ "$a" != "$b" ]
这个操作符将在[[]]结构中使用模式匹配.
< 小于,在ASCII字母顺序下.如:
if [[ "$a" < "$b" ]]
if [ "$a" < "$b" ]
注意:在[]结构中"<"需要被转义.
> 大于,在ASCII字母顺序下.如:
if [[ "$a" > "$b" ]]
if [ "$a" > "$b" ]
注意:在[]结构中">"需要被转义.
具体参考Example 26-11来查看这个操作符应用的例子.
-z 字符串为"null".就是长度为0.
-n 字符串不为"null"
注意:
使用-n在[]结构中测试必须要用""把变量引起来.使用一个未被""的字符串来使用! -z
或者就是未用""引用的字符串本身,放到[]结构中。虽然一般情况下可
以工作,但这是不安全的.习惯于使用""来测试字符串是一种好习惯.
awk '{print $2}' class.txt | grep '^[0-9.]' > res
iptables 配置文件目录 /etc/sysconfig/iptables
1.别名 alias,存放位置 $HOME/.bashrc
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 ${file1}+${file2}
--------------------位置变量:$0 $1...$9
$0:脚本的名字
$1:脚本的第一变量
$2:脚本的第二变量
向脚本中使用位置参数:./test.sh a b c
向系统命令传递参数
find /root/ -name $1 -print
./test.sh aa
标准变量:bash默认的,可以在/etc/profile中定义
EXINIT
HOME
IFS:设置分隔符,默认为空格 IFS=":"SHE
LOGNAME
MAIL 默认邮箱位置
MAILPATH多个邮箱时可以设置
TERM 显示终端类型
PS1 当前shell目录格式PS1="WANGJIAN:"
ps2 >
pwd显示当前路径 SHELL 显示当前shell
MANPATH TERMINFO
----------------------------------------------------------特殊变量
$# 变量的个数 $* 显示脚本全部参数(参数列表)
$$脚本运行的当前id号
$?显示前一个命令的运行状态
$!后台运行的最后一个进程id号
#!/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"
shift
echo "count:$#"
echo "all list:$*"
echo "pid:$$"
echo "status:$?"
./tesh.sh a b c
declare :设置或显示变量 -f只显示函数名
export:创建环境变量 -p显示所有环境变量
readonly:设置只读变量,不能修改删除
unset:取消变量的定义。-f 删除只读变量
shift:输入的位置变量改变位置 shift 表位置上移一个位置,shift 2 表上移动两个位置
双引号"":引用字符或字符串除$ `
单引号'':直接引用为字符或字符串
反引号``: 作为系统命令执行 echo `echo wangjian` wangjian
反斜杆:转义特殊字符($*?)为普通字符
运算符:~取反 << >>移位 &与(同1为1,否0) |或(有1为1,全0为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 nnn"
-n 回车不换行,默认换行 echo -n "this is a cat"
转义字符(c回车不换行 f禁止 t跳格相当tab n回车换行)
read:可以从键盘或文件的某一行文本中读入信息,并将其赋给一个变量。
read varible1 varible2
如果只指定了一个变量,那么read将会把所有的输入赋给改变量,直至遇到文件结束或回车。如果多个变量,就依次赋给。shell用空格作为变量之间的分隔符。
echo -n "first name:"
read firstname
echo -n "last name:"
read lastname
echo -e "your first name :${firstname}n"
echo -e "your last name :${lastname}n "
read -t 5 variable 5秒钟超时
read -p "Please enter your Username: " user -p prompt 提示语
[root@ceshiji ~]#Please enter your Username:
read -s -p "Please enter your Password: " pass -s charaters are not echoed. 字符不回显示。指输入之后,不在回显
cat:显示文件内容,创建文件,还可以用它来显示控制字符
cat file1 file2 file3 同时显示
cat file1 file2 file3>myfile
cat -v dos.txt (-v 显示控制符)
管道|:一个命令的输出传给一个命令的输入
df -k|awk '{print $1}'|grep -v 'Filesystem'
tee:把输出的一个副本输送到标准输出,另一个副本拷贝到相应的文件中。
tee files 在看见输出的同时,也将其存入一个文件。一般用于管道之后。
tee -a files 追加到files中 (-a 表追加)
who|tee who.out
标准输入 0
标准输出 1
标准错误 2
重定向:改变程序运行的输入来源和输出来源。
> >> < <<
command>>filename 2>&1
command
if语句必须以单词fi终止
if $x=sedsrc;then
echo
then
echo
fi
if [ "10" -lt "12" ]
man test
echo -n "enter your name:"
read NAME
if [ "$NAME" == ""];
then
echo "you did not enter any information"
else
echo "your name is $NAME"
fi
if cp myfile.bak myfile;
then
echo "GOOD COPY"
else
echo "basename $0 :error could not copy the files" >&2
case:多选择语句。如果匹配成功,执行匹配的命令
case 值 in
模式1)
命令1
;;
模式2)
命令2
;;
esac
*表任意字符,?表任意单字符 []表范围
echo -n "enter a number from 1 to 3;"
read ANS
case $ANS in
1)
echo "you select 1"
;;
2)
echo "you select 2"
;;
3)
echo "you select 3"
;;
*)
echo "basename $0 :this is not between 1 and 3" >&2
;;
esac
case $1 in
get|GET)
create_dir
get_config_file
;;
put|PUT)
put_config_file
;;
stop|STOP)
stop_server
;;
start|START)
start_server
;;
restart|RESTART)
restart_server
;;
*)
echo
echo "$Color_err Useage: ./Configure_squid.sh get|put|stop|start|restart $Color_end"
echo
exit 1
;;
esac
for
for 变量 in 列表
do
命令1
命令2
done
for语句 :提供循环执行
使用格式:
for var in values #var是变量 values是一组值
do
语句 #可以是多条语句
done
注意values的值可以全部列出,也可是通配的方式,也可以是某命令的输出值(如$(ls))。
values的值可以是:
1.列表 in 1 2 3 4 5 用空格隔开
2.文件 in file1 file2 file3
3.变量 in $a 命令输出赋值
4.命令 in `ls abc*`
5.字符串表 in "orange red blue gray"
5.特殊: 有时没有in 此时将命令行参数传入
for loop
do
find / -name $loop -print
done
[root@localhost ~]# ./sh match
/root/match
[root@localhost ~]# cat sh
#!/bin/bash
for loop
do
find /root -name $loop -print
done
#!/bin/sh
for ((i = 1; i < 254; i++)) #必须用两个括号
do
arping -I eth0 60.191.82.$i -c 1
done
arp -a > mac_table
当变量值在列表里,for循环即执行一次所有命令,使用变量名访问列表中的取值。命令可为任何有效的shell命令和语句。变量名为任意单词。in列表用法是可选的,如果不用它,for循环使用命令行的位置参数。in列表可以包含替换、字符串和文件名。
for((i=1;i<=10;i=i+1))
do
touch ar_$i;
touch full_$i;
done;
for i in {1..100}
do
.......
done
#!/bin/sh
for i in `seq 1 100`
do
echo $i
done
for loop in 1 2 3 4
do
echo $loop
done
for loop in "orange red blue grey"
do
echo $loop
done
for i in $(ls); do du -sh $i; done | sort -n 查看当前目录的大小按小--大排列
until 条件
do
命令1
命令2
...
done
条件可为任意测试条件,测试发生在循环末尾,因此循环至少执行一次.
read look
until [ "$look" ]
do
echo "full"
done
sleep 1
nohup ./test.sh &
while 命令
do
命令1
命令2
...
done
$ cat "filelist.txt"
name.txt□
txtf
□a□b□c□
$ while read file; do echo "$file"; done < "filelist.txt"
name.txt
txtf
a□b□c
echo "press ctrl+d ,stop"
while echo -n "enter a file for you like:" ; read film
do
echo " Yeah ,${file} is a good film "
done
while read line
do
echo $line
done<name.txt
break [n]:跳出循环,如果是在一个嵌入循环里,可以指定n来跳出的循环个数
continue:跳过循环步骤(本次循环)
continue只能跳过本次循环。
while :