Shell简明教程
简介
-
sh
是Unix最初使用的shell,Linux默认为bash
,是sh
的扩展。 -
source <FileName>
:在当前bash环境下,读取并执行FileName
中的命令,该FileName
可以无执行权限,该命令可以用命令.
代替; -
sh <FileName>
或者bash <FileName>
:打开子shell来读取并执行FileName
中的命令,该FileName
可以无执行权限; -
./<FileName>
:打开子shell来读取并执行FileName
中的命令,该FileName
需要执行权限。
shell变量
-
定义变量:
var_name="linxi"
-
使用变量:
echo $var_name
或者echo ${var_name}
,后者使用变量时加入了花括号{}
,这是可选的,加不加都行,但是推荐加上,以便帮助shell界定变量名的边界。比如echo ${var_name}Script
,去掉花括号,shell将认为变量名为var_nameScript
,而非var_name
。 -
只读变量:
readonly
。比如:
var_name="my var"
readonly var_name
-
删除变量:
unset
,unset <var_name>
。 -
shell字符串
-
单引号:单引号的任何字符串都会原样输出,单引号内的变量名是无效的;
-
双引号:双引号内可以有变量,双引号里可以出现转义字符。
-
获取字符串长度:
string="12" echo ${#string}
- 提取子字符串:
echo ${string:1:4}
-
-
shell数组:用括号表示数组,数组元素用空格隔开,一般形式:
arr_name=(val1 val2 val3)
或者
arr_name=(val1 val2 val3)
-
读取数组:
${var_name[index]}
-
获取数组中所有元素:
${arr_name[@]}
-
获取数组长度:
${#arr_name[@]}
或者${#arr_name[#]}
-
shell传递参数
向shell脚本内传递参数,脚本内获取参数的格式为:$n
,其中n
表示以一个数字,1
是执行脚本的第一个参数,2
是第二个参数……0
是执行的脚本名。
-
在向shell脚本传递的参数中如果包含空格,应该使用单引号或者双引号将该参数括起来,以便脚本将该参数作为整体接收;
-
shell重点中括号(包括单中括号
[]
和双中括号[[]]
)可用于一些条件的测试:-
算法比较,比如检查一个变量是否是0,应写作
[ $var_name -eq 0 ]
-
文件属性,比如确定一个文件是否存在,应写作
[ -e $file ]
;一个目录是否存在,应写作[ -d $dir ]
; -
字符串比较,比如比较两个字符串是否相同:
[[ "$string1" = "$string2" ]]
。
-
shell基本运算符
原生shell不支持简单的数学运算,但可以通过其他命令实现,例如awk
和expr
,其中expr
最常用,比如两数字相加:
val=`expr 2 + 2` # 注意,表达式和运算符之间必须要有空格,例如“2+2”是不正确的,应为“2 + 2”
val=$(expr 2 + 2) # 完整的表达式要被``包裹
- 算术运算符
+
,-
,\*
,/
,%
,=
,==
,!=
。例如:
if [ $a != $b ]; then
echo "a不等于b"
fi
- 关系运算符
-eq
(equal),-ne
(negative equal),-gt
(greater than),lt
(less than),-ge
(greater equal),-le
(less equal)
if [ $a -le $b ]; then
echo "$a -le $b: a小于等于b"
else
echo "$a -gt $b: a大于b"
fi
- 布尔运算符
!
(非运算)
# echo "!false"
flag=false
if [ !${flag} ]; then
echo "!${flag}"
else
echo "NO!"
fi
-o
(或运算)
# echo "1 -lt 2 -o 2 -lt 2"
a=1
b=2
if [ $a -lt 2 -o $b -lt 2 ]; then
echo "$a -lt 2 -o $b -lt 2"
else
echo "NO!"
fi
-a
(与运算)
# echo "1 -le 2 -o 2 -le 2"
a=1
b=2
if [ $a -le 2 -a $b -le 2 ]; then
echo "1 -le 2 -a 2 -le 2"
else
echo "NO!"
fi
-
逻辑运算符,
&&
逻辑AND,||
逻辑OR -
字符串运算符
-
==
检查两个字符串是否相等,相等返回true -
!=
检测字符串不相等 -
-z
检测字符串的长度是否是0,长度是0就返回true -
-n
检测字符串的长度是否不是0,长度不是0就返回true
- 文件测试运算符
-d <dir>
检查<dir>
是否是目录,如果是目录则返回true
# echo "/home/my_dir is dir"
dir_path=/home/my_dir # this is the path of one directory
if [[ -d ${dir_path} ]]; then
echo "${dir_path} is dir"
else
echo "NO!"
fi
-
-f <file>
检查<file>
是否是文件,如果是文件则返回true -
-e <file>
检查文件或者目录<file>
是否存在,如果存在返回true -
-x <file>
检查文件是否可执行 -
-s <file>
检查文件是否为空
Tricks
-
在判断条件中推荐使用
[[]]
而非[]
可以避免脚本中的逻辑错误,比如&&
和||
,以及操作符>
和<
都存在于[[]]
中,而不能存在于[]
中; -
[]
表达式:在[]
表达式中,常见的>
,<
需要加转义字符; -
[[]]
表达式:支持<
,>
且不需要转义字符,并且支持||
,&&
逻辑运算符,在[[]]
中不适用-a
,-o
。
字符串输出
echo
输出字符串。
-
>
重定向输出至某位置,没有则新建,清空原有内容; -
>>
重定向追加至某位置,没有则新建,追加内容。 -
2 >
重定向错误输出 -
2 >>
重定向错误,追加输出到文件结尾 -
& >
混合错误和正确输出
shell流程控制
if else
if condition1; then
command1
elif condition2; then
command2
elif condition3; then
command3
else
command4
fi
例:
a=10
b=20
if [ $a == $b ]; then
echo "$a == $b"
elif [ $a -gt $b ]; then
echo "$a greater than $b"
fi
for
for var in item1 item2 itemN; do
command
done
或者
for((assignment;condition;next)); do
command
done
while
while condition; do
command
done
例:
i=1
while(($i<=5)); do
echo "i is $i"
let "i++"
done
无限循环:
while
do
command
done
或者
while true:
do
command
done
或者
for((;;))
until
循环:与while
的condition相反
until condition
do
command
done
-
case
:多选择语句 -
break
:跳出循环 -
continue
:跳出本步循环
输入/输出重定向
如果希望将stdout
和stderr
合并后重定向到file
,则可以这样写:
command > file 2>&1
或者
command >> file 2>&1
2>1
表示将stderr
重定向到当前路径下文件名为1
的普通文件中;而2>&1
表示将stderr
重定向到文件描述符为1
的文件(也即/dev/stdout)中,这个文件其实是stdout
在文件系统中的映射。
例如:
find /etc -names "*.txt" > list 2>&1
上例中,命令从左向右执行,执行至list时,此时标准输出stdout
为list;而执行到2>&1
时,则表示stderr
也重定向到stdout
,在本例中即是list文件;
又由于find
命令的参数应为-name
而非-names
,因此会发生错误,错误信息2>&1
,重定向至标准输出,也就是list
文件。此时屏幕不会出现错误信息,而全部打印到list
文件中。
例:
# 屏蔽所有输出
command > /dev/null 2>&1