文件重定向:
标准输入stdin - 0 (默认情况)
标准输出stdout - 1
标准错误 stderr - 2
将输出和错误重定向到不同的文件:
command 1>out.txt 2>error.txt
command >out.txt 2>error.txt
检查文件内容:
cat error.txt
重定向两个流到同一个文件:
command >>out_err.txt 2>>out_err.txt
‘>>’表示附加文件,而不是覆盖文件。
command >out_err.txt 2>&1
错误输出将被重定向到流1,该流被重定向到同一个文件。
重定向工具‘管道‘,使用|(管道)符号,通常重定向stdout流。
在文件中搜索‘Hello‘字串,使用grep命令:
grep Hello text_file.txt
重定向一个命令的stdout到另一个命令的stdin流:
# fdisk -l | grep “Disk /dev”
把fdisk stdout重定向到了grep stdin.
运行脚本:
./note.sh
运行当前文件夹下的文件note.sh
# cat note.sh
文件内容:
#!/bin/bash
echo “phone number ?”
默认的用户shell将调用/bin/bash,而只有在那个时候,脚本中的命令才会被执行。
变量:
Bash shell中,用$(美元)符合来表明一个变量
#!/bin/bash
echo “Phone number ?”
read phone
echo “Name ?”
read name
echo “Issue?”
read issue
运行文件: # ./note.sh
将输入内容重定向到文件data.txt:
echo “$phone/$name/$issue”>>data.txt
查看文件note.sh最后两行:
# tail -2 note.sh
read issue
echo “$phone/$name/$issue”>>data.txt
添加日期:
date “+%Y-%m-%d %H:%M:%S”
文件中添加日期:`(反引号,不是单引号,和波浪号~同一个键位)
now = `date “+%Y-%m-%d %H:%M:%S”`
完整脚本:
#!/bin/bash
now = `date “+%Y-%m-%d %H:%M:%S”`
echo “Phone number ?”
read phone
echo “Name ?”
read name
echo “Issue?”
read issue
echo “$phone/$name/$issue”>>data.txt
改进,使用-p键加上信息,再使用循环:
#!/bin/bash
while true
do
read -p “Phone number: ” phone
now = `date “+%Y-%m-%d %H:%M:%S”`
read -p “Name: ” name
read -p “Issue: ” issue
echo “$now/$phone/$name/$issue”>>data.txt
done
按[Ctrl]+[C]退出循环。
使用cut将重定向结果切成一块一块的(按‘/‘分割),打印第二个字段,然后再排序:
cat data.txt | cut -d”/” -f2 | sort
统计唯一条目,只需要添加-c键到uniq命令:
cat data.txt | cut -d”/” -f2 | sort | uniq -c
最后更新,脚本:
#!/bin/bash
while true
do
read -p "Phone number: " phone
now=`date "+%Y-%m-%d %H:%M:%S"`
read -p "Name: " name
read -p "Issue: " issue
echo "$now/$phone/$name/$issue">>data.txt
echo "====== we got calls from ======"
cat data.txt | cut -d"/" -f2 | sort | uniq -c
echo "--------------------------------"
done
#!告诉系统其后路径所指定的程序即是解释此脚本文件的shell程序。
像#!/bin/sh,也可以改为#!/bin/bash
执行脚本:
./note.sh
一定要写成./note.sh,而不是note.sh,运行其他二进制也一样。
直接写成note.sh, Linux系统会去PATH里寻找有没有叫note.sh的文件,而只有/bin,/sbin,/usr/bin,/usr/sbin等在PATH里,而当前目录通常不在PATH里,所以写成note.sh是会找不到命令的,要用./note.sh告诉系统,在当前目录找。
可直接运行解释器:
/bin/sh note.sh
A,定义变量时,变量名和等号之间不能有空格
B,使用变量,在变量名前面加美元符号即可
your_name=’qinjx’
echo $your_name
echo ${your_name}
加花括号是为了帮助解释器识别变量的边界
C,删除变量:使用unset命令
unset your_name
d,使用help命令查看保留的关键字
e,只读变量:使用readonly命令定义只读变量
f,使用双引号或单引号来定义字符串,双引号里可以有变量,但单引号里的变量是无效的,会原样输出。
G,双引号里可以出现转义字符: \n \t \’’
H,注释一行:以 # 开头的行就是注释
I,注释多行:
:<<EOF
注释内容…
注释内容…
注释内容…
EOF
EOF也可以换成其他符号
J,定义数组:用括号来表示数组,数组元素用"空格"符号分割开
array_name=(value0 value1 value2 value3)
读取数组,使用下标:
valuen=$(array_name[n])
获取数组所有元素,使用@符号:
echo ${array_name[@]}
获取数组长度:
Length=${#array_name[@]}
Length=${#array_name[*]}
获取数组单个元素的长度:
Length=${#array_name[n]}
#!/bin/bash
array_name=(A B "C" D)
echo ${array_name[@]}
echo ${array_name[*]}
echo ${array_name[0]}
echo ${array_name[1]}
echo ${array_name[2]}
echo ${array_name[3]}
运行结果:
A B C D
A B C D
A
B
C
D
表达式:
val=`expr 2 + 2`
echo "sum is $val"
表达式和运算符之间要有空格,必须写成’2 + 2‘;表达式要用反引号` `包含.
#!/bin/bash
a=10
b=20
if [ $a == $b ]
then
echo "a equal b"
fi
if [ $a != $b ]
then
echo "a not equal b"
fi
val=`expr $a \* $b`
echo "a * b is $val"
运行结果:
a not equal b
a * b is 200
算术运算符:‘+ - * / %(取余) =(赋值) == !=’
关系运算符只支持数字,不支持字符串,除非字符串的值时数字。运算符:
‘-eq -ne -gt -lt -ge -le’
布尔运算符:‘!(非) -o(或) -a(与) ’
#!/bin/bash
if [ $a -lt 20 -a $b -gt 10 ]
then
echo "a less than 20 and b great than 10: return True"
else
echo "a not less than 20 and b not great than 10: return False"
fi
运行结果:
a less than 20 and b great than 10: return True
逻辑运算符:‘&&(逻辑与) ||(逻辑或)’
字符串运算符:‘= != -z(检测字符串长度是否为0,为0返回true) -n(检测字符串长度是否不为0,不为0返回true) $(检测字符串是否为空,不为空返回true)’
#!/bin/bash
val1="abc"
val2="efg"
if [ -z $varl ]
then
echo "-z $val1 length is not zero"
else
echo "-z $val1 length is zero"
fi
if [ $val1 != $val2 ]
then
echo "$val1 != $val2: a not equal to b"
else
echo "$val1 = $val2: a equal to b"
fi
运行结果:
-z abc length is not zero
abc != efg: a not equal to b
文件检测运算符:
-b file 检测文件是否是块设备文件,如果是,则返回true
-c file 检测文件是否是字符设备文件
-d file 检测文件是否是目录
-f file 检测文件是否是普通文件,如果是,则返回true
-g file 检测文件是否设置了SGID位
-k file 检测文件是否设置了粘着位
-p file 检测文件是否是有名管道,如果是,则返回true
-u file 检测文件是否设置了SUID位,如果是,则返回true
-r file 检测文件是否可读,如果是,则返回true
-w file 检测文件是否可写,如果是,则返回true
-x file 检测文件是否可执行,如果是,则返回true
-s file 检测文件是否为空(文件大小是否大于0),不为空返回true
-e file 检测文件(包括目录)是否存在,如果是,则返回true
#!/bin/bash
file="/var/www/runoob/test.sh"
if [ -e $file ]
then
echo "file exist"
if [ -r $file ]
then
echo "file can read"
else
echo "file can not read"
fi
else
echo "file not exist"
fi
if [ -r $file ]
then
echo "file can read"
else
echo "file can not read"
fi
运行结果:
file not exist
file can not read
显示换行:echo -e "ok! \n" #-e开启转义, \n换行
显示不换行:echo -e "ok! \c" #-e开启转义,\c不换行
原样输出,不转义或取变量(单引号):echo '$name\"'
#!/bin/bash
echo `date`
echo -e "ok! \c" #-e开启转义,\c不换行
echo "It is a test"
echo -e "ok! \n" #-e开启转义, \n换行
echo "It is a test"
echo '$name\"'
运行结果:
Mon 29 Mar 2021 12:52:54 PM UTC ok! It is a test ok! It is a test $name\"
printf格式控制输出:
printf “%-10s %-8s %-4s\n” name sex weight(kg)
printf “%-10s %-8s %-4.2f\n” guojing male 66.1234
printf转义序列:
\a 警告字符
\b 后退
\c 抑制换行
\f 换页
\n 换行
\r 回车
\t 水平制表符
\v 垂直制表符
\\ 一个字面上的反斜杠字符
\ddd 表示1到3位八进制值的字符,仅在格式字符串中有效
\0ddd 表示1到3位八进制值字符
Shell test命令:
数值测试: -eq -ne -gt -ge -lt -le
字符串测试: = != -z -n
文件测试:-e -r -w -x -s -d -f -c -b
#!/bin/bash
num1=100
num2=200
if test $[num1] -eq $[num2]
then
echo "they are equal"
else
echo "they are not equal"
fi
result=$[num1+num2]
echo "result is $result"
num1="run1oob"
num2="runoob"
if test $num1 = $num2
then
echo "they are equal"
else
echo "they are not equal"
fi
if test -e ./bash
then
echo "file is existed"
else
echo "file is not existed"
fi
运行结果:
they are not equal
result is 300
they are not equal
file is not existed
shell流程控制:
if [ $(ps -ef | grep -c “ssh”) -gt 1 ]; then echo “true”; fi
for str in this is a string
do
echo $str
done
int=1
while(( $int <= 5 ))
do
echo $int
let "int++"
done
a=0
until [ ! $a -lt 10 ]
do
echo $a
a=`expr $a + 1`
done
运行结果:
this
is
a
string
1
2
3
4
5
0
1
2
3
4
5
6
7
8
9
echo "input number 1-4:"
echo "your input:"
read aNum
case $aNum in
1) echo "your input 1"
;;
2) echo "your input 2"
;;
3) echo "your input 2"
;;
4) echo "your input 4"
;;
*) echo "your input not in 1-4"
;;
esac
运行结果:
input number 1-4:
your input:
your input not in 1-4
break 命令:跳出所有循环
continue 命令:跳出当前循环
带参数的函数:
在函数体内部,通过$n的形式来获取参数的值,$10不能获取第十个参数,获取第十个参数需要${10}。当n>=10时,需要使用${n}来获取。
函数返回值在调用函数后通过 $? 来获得。
#!/bin/bash
funWithReturn(){
echo "the first param $1"
echo "the second param $2"
echo "the third param $3"
echo "the tenth param $10"
echo "the tenth param ${10}"
echo "the eleventh param ${11}"
echo "the count of params: $# !"
echo "output all params as one string: $* !"
}
funWithReturn 1 2 3 4 5 6 7 8 9 34 73
echo $?
function fun1(){
echo "this is the first function"
return `expr 1 + 1 `
}
fun1
echo $?
echo $?
运行结果:
the first param 1
the second param 2
the third param 3
the tenth param 10
the tenth param 34
the eleventh param 73
the count of params: 11 !
output all params as one string: 1 2 3 4 5 6 7 8 9 34 73 !
0
this is the first function
2
0
几个特殊字符用来处理参数:
$# 传递到脚本或函数的参数个数
$* 以一个单字符串显示所有向脚本传递的参数
$$ 脚本运行的当前进程ID
$! 后台运行的最后一个进程ID号
$@ 与$*相同,但是使用时加引号,并在引号中返回每个参数
$- 显示shell使用的当前选项,与set命令功能相同
$? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误
输入/输出重定向:
command > file
command < file
command >> file
command << file
command < infile > outfile
command >> file 2>&1
command > /dev/null 2>&1 #将命令的输出重定向到文件/dev/null中,/dev/null文件是一个特殊的文件,写入到它的内容都会被丢弃。
通过‘wc -l’命令计算内容的行数;
0是标准输入(STDIN),1是标准输出(STDOUT),2是标准错误输出(STDERR)。
Shell文件包含:
. filename # 点号(.)和文件中间有一个空格
或
source filename
#!/bin/bash
# import file ./test1.sh
. ./test1.sh
echo "import file"
if test -e ./test1.sh
then
echo "file is existed"
else
echo "file is not existed"
fi
运行结果:
import file
file is not existed
script.sh: line 174: ./test1.sh: No such file or directory