1、给变量赋值的时候,变量、等号、值之间不能有空格
2、如何将一个命令的输出赋值给一个变量?
使用`符号,比如将date命令的输出赋值给a这个变量
a=`date`或者a=$(date)
这个用法很有意义,比如说可以用在日志文件的生成上面:
#!/bin/sh
file=`date +%Y%m%d`
ls > ${file}.log
3、export一个变量,对子进程的影响
如果一个变量没有export,那么这个变量是不会加入到当前shell的环境变量的,因此子进程也不会看到这个变量的值。
4、子进程与子shell的区别
先看一段代码:
unset abcd
abcd=1
(echo "a=${a}")
sh -c 'echo a=${a}'
这段代码的输出:
a=1
a=
首先说明一下,把命令括起来是什么意思:使用子shell执行这条命令。
sh -c 'echo a=${a}'这条命令是生成一个子进程来执行这条命令
子shell输出了a=1,因为子shell其实是父进程fork出了一个子进程,这个子进程和父进程几乎是一样的(除了一些没办法赋值的量),当然a也被复制了一份,所以子shell输出a=1;但是sh -c 'echo a=${a}'这条命令也是父进程fork出一个子进程执行这条命令,但是在fork之后,执行了exec函数,重新执行了bash程序,因此代码段、变量什么的都被新的程序替换了,因此a的值也就是空,但是注意到在执行exec函数的时候,会传进去环境变量。这也是为什么export之后的变量可以在子进程中看到的原因。
5、在使用管道时,Linux系统实际上会同时运行管道符号前后的两个命令,在系统内部将它们连接起来。在第一个命令产生输出的同时,输出会被立即送给第二个命令。数据传输不会用到任何中间文件或缓冲区。
测试程序:
test.sh
#!/bin/bash
echo "abcd"
sleep 3
echo "efg"
在shell里面运行./test.sh | cat
可以看到第一个命令还没执行完就有了输出。
6、if语句
(1)格式:
if command
then
command
fi
记住if判断的是command是否退出状态为0,而不是command执行完是true还是false。
(2)if-then-else语句
格式:
if command
then
command
else
command
fi
(3)if-then-elif
格式:
if command
then
command
elif command
then
command
fi
我们一般在程序中是要判断条件是否成立,但是这里只能判断命令的退出状态,有什么命令可以满足这种需求呢,有!,这个命令就是test,这个命令如果不成立,则返回状态不为1,成立则返回状态0.
7、if判断的几种类型
(1)数值比较
n1 -eq n2 n1是否等于n2
n1 -ne n2 n1是否不等于n2
n1 -ge n2 n1是否大于或等于n2
n1 -gt n2 n1是否大于n2
n1 -le n2 n1是否小于等于n2
n1 -lt n2 n1是否小于n2
(2)字符串比较
str1 = str2 str1是否等于str2,=两边要有空格,否则为赋值了
str1 != str2 str1是否不等于str2
str1 < str2 str1是否小于str2
str1 > str2 str1是否大于str2
-n str1 str1长度是否非0
-z str1 str1长度是否为0,即为NULL
(3)文件比较
-d file 检查file是否存在并是一个目录
-e file 检查file是否存在
-f file 检查file是否存在并是一个文件
-r file 检查file是否存在并可读
-s file 检查file是否存在并非空
-w file 检查file是否存在并可写
-x file 检查file是否存在并可执行
-O file 检查file是否存在并属当前用户所有
-G file 检查file是否存在并且默认组与当前用户相同
file1 -nt file2 检查file1是否比file2新
file1 -ot file2 检查file1是否比file2旧
(4)逻辑判断
-a 与
-o 或
! 非
8、复合条件测试
[ condition1 ] && [ condition2 ]
[ condition1 ] || [ condition2 ]
9、for循环
格式:
for var in list
do
commands
done
比如,打印当前目录下面所有的文件名(不包括隐藏文件)
#!/bin/bash
for test in *
do
echo $test
done
值list的列表默认是使用空格分隔的,若值本身就包含空格,那么使用双引号把值包起来,双引号并不作为值的一部分。
10、while循环
while test command
do
other commands
done
11、如何使用数值型变量
使用let命令
比如我们需要打印当前文件夹下面的前十个文件
#!/bin/bash
let i=0
for file in *
do
if [ $i -ge 10 ]
then
break
else
let i++
echo $file
fi
done
12、如何处理命令行参数
在需要对命令传参数时,我们可以使用一些特殊的变量
$# 命令行参数的个数
$0 命令的名称
$1 命令行的第一个参数
$2 命令行的第二个参数,依此类推
$? 上一次命令的退出状态
$* 全部命令行参数
$@ 全部命令行参数,与$*稍有差别
在运行脚本时我们可能会对脚本传进一些参数,以此来决定控制脚本的运行行为:例如
./test.sh -a -b input.txt
假设这个命令行的意思是test.sh这个脚本使用了-a这个选项,也使用了-b这个选项,并且-b这个选项还带了一个参数input.txt,那么怎么在程序中识别这些参数呢。
最简单的就是在程序中使用case,对有效的选项进行判断,例如:
#!/bin/bash
while [ -n "$1" ]
do
case "$1" in
-a) echo "option -a";;
-b) para=$2
echo "option -b with para $para"
shift;;
# 默认--后面的参数是作为命令行的参数,而不是选项的参数
--) shift
break;;
*) echo "$1 is not a option";;
esac
shift
done
root@ubuntu:~/traninig/shell_test$ ./test.sh -a -b 1
option -a
option -b with para 1
这样当然是比较简单的命令选项,当遇到组合选项怎么办,例如:
./test.sh -ab 1
这时候就要使用getopt这个命令来解析选项,解析选项的格式是这样的
getopt 选项排列(如选项带参数,则选项后面加冒号) 命令选项
仍使用上面的例子,使得./test.sh -ab 1能够正确解析
root@ubuntu:~/traninig/shell_test$ getopt ab: -ab 1
-a -b 1 --
说明:
getopt 解析组合选项的命令
ab: 说明需要使用的选项,都是单个字母一个选项
-ab 1 组合选项
输出:-a -b 1 -- 这个就是简化了的命令行选项参数,可以使用上面的办法进行解析
把这个使用到程序中
#!/bin/bash
#set命令将--后面的内容设置成命令行参数,也就是$@
set -- $(getopt ab: "$@")
while [ -n "$1" ]
do
case "$1" in
-a) echo "option -a";;
-b) para=$2
echo "option -b with para $para"
shift;;
--) shift
break;;
*) echo "$1 is not a option";;
esac
shift
done
测试:
root@ubuntu-146:~/traninig/shell_test$ ./test.sh -ab 1
option -a
option -b with para 1
但是这个getopt不能处理参数里面有空格
root@ubuntu-146:~/traninig/shell_test$ ./test.sh -ab "1 2"
option -a
option -b with para 1
2 is not a option
为了能够在命令选项参数中使用空格,需要使用getopts命令进行选项参数的解析,getopts的使用和getopt的使用方法有较大的不同
#!/bin/bash
while getopts ab: opt
do
case "$opt" in
a) echo "option -a";;
b) echo "option -b with para $OPTARG";;
*) echo "unknown option $OPTARG";;
esac
done
首先,getopts的使用就不同,getopts首先就在内部把$@的内容解析好,然后依次填入opt进行判断,而且解析出来的内容也不同于getopt,很明显getopts解析出来的选项没有-,所以case中,选项的前面都没有-,另外还有两个环境变量,OPTARG和OPTIND,如果选项携带参数,那么OPTARG的内容就是参数,OPTIND代表getopts处理参数的位置,每处理完一个参数,OPTIND就会加1.这个OPTIND参数可以使用在传给命令的参数上面:
#!/bin/bash
while getopts ab: opt
do
case "$opt" in
a) echo "option -a";;
b) echo "option -b with para $OPTARG";;
*) echo "unknown option $OPTARG";;
esac
done
shift $[ $OPTIND-1 ]
count=1
for para in "$@"
do
echo "#para${count} : ${para}"
shift
let count++
done
13、输入输出重定向
输入重定向:
exec 3<&0 #将3重定向到0,也就是保存了标准输入
exec 0< inputfile #将标准输入重定向到inputfile这个文件
exec 0<&3 #将0重定向到3,恢复标准输入
exec 3>&- #将3重定向到-,这是一个特殊的描述符,意思就是关闭3
相应的,输出重定向:
exec 3>&1 #将3重定向到1,也就是保存了标准输出
exec 1> inputfile #将标准输出重定向到inputfile这个文件
exec 1>&3 #将1重定向到3,恢复标准输出
exec 3>&- #将3重定向到-,这是一个特殊的描述符,意思就是关闭3
重定向标准输入输出所使用的符号不一样,输出是">",输入时"<",除此之外基本相同。
当然也可以把一个文件描述符重定向到输入输出,但是这样可能会出现一些问题
14、多命令执行";“和“&&”
当使用”;“时,不论前面的命令是否执行成功,后面的命令都会执行
使用”&&"时,只有前面的命令都执行成功,后面的命令才会执行