基本语法
echo 命令
脚本中会大量用到echo命令输出执行日志
1 | # 单行 |
常用参数
-n
默认情况下,echo
输出的文本末尾会有一个回车符。-n
参数可以取消末尾的回车符,使得下一个提示符紧跟在输出内容的后面。
1 | $ echo -n hello world |
-n
参数可以让两个echo
命令的输出连在一起,出现在同一行。
-e
-e
参数会解释引号(双引号和单引号)里面的特殊字符(比如换行符\n
)。如果不使用-e
参数,即默认情况下,引号会让特殊字符变成普通字符,echo
不解释它们,原样输出。
1 | $ echo "Hello\nWorld" |
变量
声明变量
变量声明方式: 变量名=变量值
, =
左右不要有空格. 变量名命名规则:
- 只能使用数字, 大小写字母, 下划线, 首字符不能为数字
- 不能有空格, 可以使用
_
- 不能使用base里的关键字(使用
help
命令查看关键字)
1 | boo |
推荐给所有变量加上花括号
1 | your="Tom" |
已定义的变量, 可以被重新赋值, 如:
1 | your_name="John" |
第二次赋值的时候不能写\$your_name=”alibaba”, 使用变量的时候才加美元符($)
只读变量
使用 readonly 命令可以将变量定义为只读变量, 只读变量的值不能被改变.1
2
3
4
myUrl="http://www.google.com"
readonly myUrl
myUrl="http://www.runoob.com"
运行时会报错1
/bin/sh: NAME: This variable is read only.
删除变量
使用 unset
命令可以删除变量1
2
3
4
myUrl="http://www.runoob.com"
unset myUrl
echo $myUrl
以上实例执行将没有任何输出
变量替换
变量替换是指可以根据变量的状态(是否为空, 是否定义等)来改变变量的值
形式 | 说明 |
---|---|
${var} | 变量本来的值 |
${var:+word} | 如果变量var被定义, 那么返回word, 但不改变变量var的值 |
${var:-word} | 变量var如果为空或已被删除(unset), 则返回word, 但不改变变量var的值 |
${var:=word} | 变量var如果为空或已被删除(unset), 则返回word, 同时将变量var的值设置为word |
${var:?msg} | 变量var如果为空或已被删除(unset), 则将msg发送到标识错误输出. 若此替换出现在脚本中, 则脚本停止运行 |
示例:
1 |
|
变量类型
- 局部变量 局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。
- 环境变量 所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量。
- shell变量 shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行
字符串
linux shell 字符串操作详解 (长度,读取,替换,截取,连接,对比,删除,位置 )
Reading output of a command into an array in Bash
1 | your_name='runoob' |
输出结果1
Hello, I know you are "runoob"!
单引号字符串的限制:
- 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
- 单引号字串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用。
双引号的优点:
- 双引号里可以有变量
- 双引号里可以出现转义字符
操作
表达式 | 含义 |
---|---|
${#string} |
$string 的长度 |
${string:position} |
在$string 中, 从位置$position 开始提取子串 |
${string:position:length} |
在$string 中, 从位置$position 开始提取长度为$length 的子串 |
${string#substring} |
从变量$string 的开头, 删除最短匹配$substring 的子串 |
${string##substring} |
从变量$string 的开头, 删除最长匹配$substring 的子串 |
${string%substring} |
从变量$string 的结尾, 删除最短匹配$substring 的子串 |
${string%%substring} |
从变量$string 的结尾, 删除最长匹配$substring 的子串 |
${string/substring/replacement} |
使用$replacement , 来代替第一个匹配的$substring |
${string//substring/replacement} |
使用$replacement , 代替所有匹配的$substring |
${string/#substring/replacement} |
如果$string 的前缀匹配$substring , 那么就用$replacement 来代替匹配到的$substring |
${string/%substring/replacement} |
如果$string 的后缀匹配$substring , 那么就用$replacement 来代替匹配到的$substring |
1 | # 字符串长度 ${#变量名}得到字符串长度 |
拼接
1 | your_name="runoob" |
子字符串
1 | # 提取子字符串 |
数组
1 | array_name=(value0 value1 value2 value3) |
注释
1 | # 以 # 开头的行就是注释, 会被解释器忽略 |
参数
脚本通过$n
获取参数1
2
3
4
5
6
7
echo "Shell 传递参数实例!";
echo "执行的文件名:$0";
echo "第一个参数为:$1";
echo "第二个参数为:$2";
echo "第三个参数为:$3";
执行脚本1
2
3
4
5
6$ ./test.sh 1 2 3
Shell 传递参数实例!
执行的文件名:./test.sh
第一个参数为:1
第二个参数为:2
第三个参数为:3
特殊参数列表
变量 | 含义 |
---|---|
$0 |
是脚本本身的名字 |
$n |
添加到sehll的各参数值.$1 是第一个参数,$2 是第二个参数,以此类推 |
$# |
传给脚本的参数个数 |
$@ |
传给脚本的所有参数的列表, 即被扩展为$1 $2 $3 等 |
$* |
以一个单字符串显示所有向脚本传递的参数, 即被扩展成\$1c\$2c\$3 , 其中c是IFS的第一个字符 |
$$ |
脚本运行的当前进程ID号 |
$? |
显示最后命令的退出状态, 0表示没有错误, 其他表示有错误 |
$! |
脚本最后运行的后台Process的进程id |
$- |
显示Shell使用的当前选项,与set命令功能相同。 |
$*
与 $@
区别:
- 相同点:都是引用所有参数。
- 不同点:只有在双引号中体现出来。假设在脚本运行时写了三个参数 1、2、3,,则 “ * “ 等价于 “1 2 3”(传递了一个参数),而 “@” 等价于 “1” “2” “3”(传递了三个参数)。
1 | echo "-- \$* 演示 ---" |
执行脚本,输出结果如下所示1
2
3
4
5
6
7$ ./test.sh 1 2 3
-- $* 演示 ---
1 2 3
-- $@ 演示 ---
1
2
3
getopt getopts
运算符
算数运算符
运算符 | 说明 |
---|---|
+ | 加法 `expr $a + $b` 结果为 30 |
- | 减法 `expr $a - $b` 结果为 10 |
* | 乘法 `expr $a * $b` 结果为 200 |
/ | 除法, 取整 `expr $b / $a` 结果为 2 |
% | 取余 `expr $b % $a` 结果为 0 |
= | 赋值 a=$b 将把变量 b 的值赋给 a |
== | 相等, 相同返回true [ $a == $b ] 返回 false |
!= | 不等, 不同返回false [ $a != $b ] 返回 true |
注意 :
- 条件表达式要放在方括号之间, 并且要有空格, 例如:
[$a==$b]
是错误的, 必须写成[ $a == $b ]
- 乘号(*)前边必须加反斜杠()才能实现乘法运算, 即写成
expr $a \* $b
- MAC 中 shell 的 expr 语法是:
$((表达式))
, 此处表达式中的*
不需要转义符号\
原生bash不支持简单的数学运算, 但可以通过一下几种方式实现:
let
1
2
3var=1;
let "var+=1";
echo $var- let几乎支持所有的运算符
- 方幂运算应使用“**”
- 变量在表达式中直接访问,不必加$
- 一般情况下算数表达式可以不加双引号,但是若表达式中有bash中的关键字则需加上
- let后的表达式只能进行整数运算
(())
推荐
(())
的使用方法与let关键字完全相同1
2
3var=1;
((var+=1));
echo $var
$[]
1
2
3var=1;
var=$[$var+1];
echo $var$[]
将中括号内的表达式作为数学运算先计算结果再输出- 对
$[]
中的变量进行访问时前面需要加$
$[]
支持的运算符与let
相同,但也只支持整数运算
expr
1
2
3var=1;
var=`expr $var + 1`;
echo $var- expr后的表达式符号间需用空格隔开
- expr支持的操作符有: |、&、< >=、<、+、-、*、/、%
- expr支持的操作符中在使用时需用\进行转义的有:|、&、< >=、<、*
- expr同样只支持整数运算
bc
bc是linux下的一个简单计算器,支持浮点数计算,在命令行下输入bc即进入计算器程序,而我们想在程序中直接进行浮点数计算时,利用一个简单的管道即可解决问题。1
2
3var=1;
var=`echo "$var+1"|bc`;
echo $var- bc支持除位操作运算符之外的所有运算符。
- bc中要使用scale进行精度设置,如scale=2设置小数点2位精度
awk
1
2
3var=1;
var=`echo "$var 1"|awk '{printf("%g",$1+$2)}'`;
echo $var- awk支持除位操作运算符之外的所有运算符
- awk内置有log、sqr、cos、sin等等函数
关系运算符
关系运算符只支持数字, 不支持字符串, 除非字符串的值是数字
表达式 | 含义 |
---|---|
-eq | 两数值相等(equal) [ $a -eq $b ] 返回 true |
-ne | 两数值不等(not equal) [ $a -ne $b ] 返回 true |
-gt | n1大于n2(greater than) [ $a -gt $b ] 返回 false |
-lt | n1小于n2(less than) [ $a -lt $b ] 返回 true |
-ge | n1大于等于n2(greater than or equal) [ $a -ge $b ] 返回 false |
-le | n1小于等于n2(less than or equal) [ $a -le $b ] 返回 true |
示例:1
2
3
4
5
6
7
8
9
10a=100
b=100
if [ $a -eq $b ]
then
echo '$a -eq $b : a 等于 b'
else
echo '$a -eq $b : a 不等于 b'
fi
# 10 -eq 10: a 等于 b
布尔运算符
运算符 | 说明 |
---|---|
! | 非运算 [ ! false ] 返回 true |
-o | 或运算 [ $a -lt 20 -o $b -gt 100 ] 返回 true |
-a | 与运算 [ $a -lt 20 -a $b -gt 100 ] 返回 false |
示例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25a=10
b=20
if [ $a != $b ]
then
echo "$a != $b : a 不等于 b"
else
echo "$a != $b: a 等于 b"
fi
# 10 != 20 : a 不等于 b
if [ $a -lt 100 -a $b -gt 15 ]
then
echo "$a 小于 100 且 $b 大于 15 : 返回 true"
else
echo "$a 小于 100 且 $b 大于 15 : 返回 false"
fi
# 10 小于 100 且 20 大于 15 : 返回 true
if [ $a -lt 5 -o $b -gt 100 ]
then
echo "$a -lt 100 -o $b -gt 100 : returns true"
else
echo "$a -lt 100 -o $b -gt 100 : returns false"
fi
逻辑运算符
运算符 | 说明 |
---|---|
&& | AND |
| | | OR |
示例:
1 | a=10 |
注意使用的是双括号
字符串运算符
运算符 | 说明 |
---|---|
= | 检测两个字符串是否相等 |
!= | 检测两个字符串是否不相等 |
-z | 检测字符串长度是否为0 |
-n | 检测字符串长度是否不为0 |
str | 检测字符串是否不为空 |
str1 > str2 |
str1字母顺序是否大于str2, 若大于, 则返回true |
str1 < str2 |
str1字母顺序是否小于str2, 若小于, 则返回true |
1 | a="abc" |
文件测试运算符
文件类检测:
表达式 | 含义 |
---|---|
-e file |
文件是否存在(exist) |
-f file |
文件是否存在且为普通文件(file) |
-d file |
文件是否存在且为目录(directory) |
-b file |
文件是否存在且为块设备block device |
-c file |
文件是否存在且为字符设备character device |
-S file |
文件是否存在且为套接字文件Socket |
-p file |
文件是否存在且为命名管道文件FIFO(pipe) |
-L file |
文件是否存在且是一个链接文件(Link) |
-h file |
文件是否存在且是一个链接文件(Link) |
文件属性检测:
表达式 | 含义 |
---|---|
-r file |
文件是否存在且当前用户可读 |
-w file |
文件是否存在且当前用户可写 |
-x file |
文件是否存在且当前用户可执行 |
-u file |
文件是否存在且设置了SUID |
-g file |
文件是否存在且设置了SGID |
-k file |
文件是否存在且设置了sbit(sticky bit) |
-s file |
文件是否存在且大小大于0字节,即用于检测文件是否为非空白文件 |
-N file |
文件是否存在,且自上次read后是否被modify |
示例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27if [ -x $file ]
then
echo "文件可执行"
else
echo "文件不可执行"
fi
if [ -f $file ]
then
echo "文件为普通文件"
else
echo "文件为特殊文件"
fi
if [ -s $file ]
then
echo "文件不为空"
else
echo "文件为空"
fi
if [ -e $file ]
then
echo "文件存在"
else
echo "文件不存在"
fi
两个文件之间比较:
表达式 | 含义 |
---|---|
file1 -nt file2 |
(newer than)判断file1是否比file2新 |
file1 -ot file2 |
(older than)判断file1是否比file2旧 |
file1 -ef file2 |
(equal file)判断file2与file2是否为同一文件, 可用在判断hard link的判定上 |
示例:1
2
3
4
5
6
7cd /bin
if test -e ./bash
then
echo '文件已存在!'
else
echo '文件不存在!'
fi
echo printf 命令
echo显示换行:1
2echo -e "OK! \n" # -e 开启转义
echo "It is a test"
结果:1
2
3OK!
It is a test
echo显示不换行:1
2echo -e "OK! \c" # -e 开启转义 \c 不换行
echo "It is a test"
结果:1
OK! It is a test
默认printf
不会像echo
自动添加换行符, 我们可以手动添加 \n
1
2
3
4$ echo "Hello, Shell"
Hello, Shell
$ printf "Hello, Shell\n"
Hello, Shell
使用格式替换符:1
2
3
4printf "%-10s %-8s %-4s\n" 姓名 性别 体重kg
printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234
printf "%-10s %-8s %-4.2f\n" 杨过 男 48.6543
printf "%-10s %-8s %-4.2f\n" 郭芙 女 47.9876
结果:1
2
3
4姓名 性别 体重kg
郭靖 男 66.12
杨过 男 48.65
郭芙 女 47.99
%s
%c
%d
%f
都是格式替代符%-10s
指一个宽度为10个字符(-
表示左对齐, 没有则表示右对齐), 任何字符都会被显示在10个字符宽的字符内, 如果不足则自动以空格填充, 超过也会将内容全部显示出来%-4.2f
指格式化为小数, 其中.2指保留2位小数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25# format-string为双引号
printf "%d %s\n" 1 "abc"
#1 abc
# 单引号与双引号效果一样
printf '%d %s\n' 1 "abc"
#1 abc
# 没有引号也可以输出
printf %s abcdef
# 格式只指定了一个参数,但多出的参数仍然会按照该格式输出,format-string 被重用
printf %s abc def
printf "%s\n" abc def
#abcdefabcdefabc
#def
printf "%s %s %s\n" a b c d e f g h i j
#a b c
#d e f
#g h i
#j
# 如果没有 arguments,那么 %s 用NULL代替,%d 用 0 代替
printf "%s and %d \n"
# and 0
test命令
test
命令用于检查某个条件是否成立, 它可以进行数字, 字符串和文件三种测试
示例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26# 两个整数之间的比较, 支持正负数, 但不支持小数.
num1=100
num2=100
if test $[num1] -eq $[num2]
then
echo '两个数相等!'
else
echo '两个数不相等!'
fi
str1="ru1noob"
str2="runoob"
if test $str1 = $str2
then
echo '两个字符串相等!'
else
echo '两个字符串不相等!'
fi
cd /bin
if test -e ./notFile -o -e ./bash
then
echo '至少有一个文件存在!'
else
echo '两个文件都不存在'
fi
各种括号的作用() (()) [] [[]]
1 | $ type [ [[ test |
test 和 [] 用法
它们根据参数的个数来完成测试, 例:
不带任何参数, 返回false.
1
2$ [ ];echo $?
1只有一个参数时, 仅当参数非空是返回true
1
2
3
4$ test "";echo $?
1
$ test "a";echo $?
0两个参数时, 有几种情况:
- 第一个参数是单目运算符, 包括文件测试, 如:
[ -e file ]
和[ -n str ]
- 第一个参数是
!
时, 则只能是[ ! str ]
, 等价于[ ! -n str ]
- 第一个参数不是任何有效的操作符, 则直接报错
- 第一个参数是单目运算符, 包括文件测试, 如:
- 三个参数时, 也有几种情况:
- 使用了双目预运算符, 如:
[ file1 -nt file2 ]
,[ int1 -eq int2 ]
- 使用了逻辑运算符, 如:
[ ! -e file ]
,[ ! -z str ]
- 使用了括号, 则只能是
[ (string) ]
- 使用了双目预运算符, 如:
[[]]
用法
用法与[]
基本相同, 但要注意一下几点:
当条件表达式中使用
==
或!=
时, 该运算符的右边会被当做pattern被匹配,==
表示能匹配成功则返回0,!=
则相反. 但只是通配符匹配, 不支持正则. 通配符包括*
,?
和[...]
1
2
3
4
5
6$ [[ abc == a* ]];echo $?
0
$ [[ abc == a*d ]];echo $?
1
$ [[ abc == a[bB]c ]];echo $?
0当条件表达式中使用的运算符是”=~”时, 该运算符的右边会被当做正则表达式的pattern被匹配
1
2
3
4$ [[ abc =~ aa* ]];echo $?
0
$ [[ abc =~ aa.* ]];echo $?
1除了可以使用逻辑运算符
!
和()
, 还可以使用&&
,||
, 等价于[]
的-a
和-o
, 但是[[]]
不在支持-a
和-o
1
2$ [[ 3 -eq 3 && 5 -eq 5 ]];echo $?
0
使用建议
无论是
[]
还是[[]]
, 建议对其中的变量, 字符串使用双引号包裹. 能做字符串比对是, 不要使用数组比较.1
2name="Tom Hanks"
[ $name = "Tom Hanks" ]上面的语句会报错, 因为在变量替换阶段,
$name
会被替换为Tom Hanks, 但它们没有在引号内, 于是进行单词拆分, 导致等价于执行[ Tom Hanks = "Tom Hanks" ]
. 所以应该这么写:1
[ "$name" = "Tom Hanks" ]
数值比对时, 建议双方都加0, 避免变量为空时报错.
1
2
3
4
5$ [ $a -eq 7 ]
-bash: [: -eq: unary operator expected
$ [ $((a+0)) -eq 7 ]; echo $? # 或者用字符串方式 [ "$a" = "7" ]
1在变量可能为空时, 建议在变量的基础上增加其他辅助字符串. 这比上面的方法更安全
1
2
3$ [ "a$a" = "a7" ] # 判断a是否为7
$ [ "a$a" = "a" ] # 判断a是否为空
$ [ ! -z "$a" -a "a$a" = "a7" ] # a不为空且a=7时才为真
流程控制
if else
语法格式如下:1
2
3
4
5
6
7
8if commands1
then
commands2
elif
commands3
else
commands4
fi
如果执行commands1
后的退出码是0, 则执行then
部分的commands2
. 退出码非0则执行elif
部分的commands3
, 以此类推. commands1
部分有如下几种写法:
if [ condition ]
: 等价于test
, 在所有的POSIX shell上都能用. 注意condition
与括号间必须有空格if [[ condition ]]
: 基本等价于[]
, 但支持更多的条件表达式, 且允许使用逻辑运算符”&&” “||” “!” 和 “()”, 还支持正则表达式匹配. 较新的bash和zsh都支持.if ((condition))
:if (command)
: 以子shell的方式运行command
if command
: 根据命令执行后的返回码为判断依据
for
语法及示例:
1 | for bar in item1 item2 ... itemN |
while
1 | while condition |
until
语法格式:1
2
3
4until condition
do
command
then
until
循环执行一系列命令, 直到condition
为true
时停止. 和while
循环刚好相反.1
2
3
4
5
6
7
8
9
a=0
until [ ! $a -lt 10 ]
do
echo $a
a=`expr $a + 1`
done
case
语法格式:1
2
3
4
5
6
7
8
9
10
11case 值 in
模式1)
command
;;
模式2)
command
;;
*)
command
;;
esac
示例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45echo '输入 1 到 3 之间的数字:'
echo '你输入的数字为:'
read aNum
case $aNum in
1) echo '你选择了 1'
;;
2) echo '你选择了 2'
;;
3) echo '你选择了 3'
;;
*) echo '你没有输入 1 到 4 之间的数字'
;;
esac
name=`basename $0 .sh`
case $1 in
s|start)
echo "start..."
;;
stop)
echo "stop ..."
;;
reload)
echo "reload..."
;;
*)
echo "Usage: $name [start|stop|reload]"
exit 1
;;
esac
exit 0
# 判断输入文件是文件还是目录
option="${1}"
case ${option} in
-f) file="${2}"
echo "file name is $file"
;;
-d) dir="${2}"
echo "dir name is $dir"
;;
*)echo "basename ${0} :usage:[-f file ]| [-d directory]"
exit 1
;;
esac
注意:
*)
相当于其他语言中的default
- 除了
*)
模式, 其他分支中的;;
是必须的, 相当于其他语言中的break
|
分隔多个模式, 相当于or
break continue
1 | while : |
跳出多次循环时使用break n
, n表示要跳出的循环层数, 默认为1.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15a=1
while [ $a -le 5 ]
do
echo "Outer loop:a=$a"
a=$[$a+1]
for val in 1 2 3 4 5
do
if [ $val -eq 3 ]
then
break 2
fi
echo " Inner loop:val=$val"
val=$[$val+1]
done
done
continue仅跳出本次循环1
2
3
4
5
6
7
8
9a=1
for val in 1 2 3 4 5
do
if [ $val -le 3 ]
then
continue
fi
echo "val=$val"
done
函数
函数定义格式如下:1
2
3
4
5[function] funcName [()]
{
//do something
[return int;]
}
说明:
- 可以使用
function foo()
定义, 也可以直接foo()
定义 - 可以加
return xx;
返回, xx的值为0-255. 如果没有return, 将以最后一条命令运行结果作为返回值.
1 |
|
函数参数
1 | paramFunc() { |
输出:1
2
3
4
5
6
7第一个参数为 1 !
第二个参数为 2 !
第十个参数为 10 !
第十个参数为 34 !
第十一个参数为 73 !
参数总数有 11 个!
作为一个字符串输出所有参数 1 2 3 4 5 6 7 8 9 34 73 !
注意: 当n>=10时, 需要使用${n}来获取参数.
当脚本有main函数, 你希望脚本运行时传递的所有命令行参数都能被main函数捕捉到, 可以这么写:1
2
3
4
5
6
7
8
9
main() {
for p in "${@}"; do
echo $p;
done
}
main "${@}"
执行结果:1
2
3
4$ ./test.sh a 12 -x
a
12
-x
同理, 当A函数调用B函数时, 希望把调用A时传递的所有参数都传递给B, 也可以这么写1
2
3
4
5
6
7A() {
B "${@}"
}
B() {
}
输入/输出重定向
一个命令通常从标准输入读取输入, 并将其输出写入标准输出. 通常都是终端. 重定向命令列表如下:
命令 | 说明 |
---|---|
command > file | 将输出重定向到file |
command < file | 将输入重定向到file |
command >> file | 将输出已追加方式重定向到file |
n > file | 将文件描述符为n的文件重定向到file |
n >> file | 将文件描述符为n的文件已追加方式重定向到file |
n >& m | 将输出文件m和n合并 |
n <& m | 将输入文件m和n合并 |
<< tag | 将开始标记tag和结束标记tag之间的内容作为输入 |
文件描述符 0 通常是标准输入(STDIN), 1 是标准输出(STDOUT), 2 是标准错误输出(STDERR)
实例
1 | $ who > users.txt |
一般情况下, 每个Unix/Linux命令运行时都会打开3个文件
- 标准输入文件(stdin): 其文件描述符为0, Unix程序默认从中读取数据
- 标准输出文件(stdout): 其文件描述符为1, Unix程序默认向其输出数据
- 标准错误文件(stderr): 其文件描述符为2, Unix程序会向stderr流中写入错误信息
如果希望stderr重定向到file, 可以这样写:1
$ command 2 > file
如果希望将stdout和stderr合并后重定向到file, 可以这样写:1
$ command > file 2>$1
/dev/null 文件
/dev/null
是一个特殊文件, 写入到它的内容都会被丢弃; 如果尝试从该文件读取内容, 则什么也读不到. 将命令的输出重定向到它, 会起到”禁止输出”的效果. 如果希望屏蔽stdout和stderr, 可以这样写:1
$ command > /dev/null 2>&1
文件包含
和其他语言一样, Shell 也可以包含外部脚本, 这样可以很方便的封装一些公用的代码作为一个独立的文件. 语法格式如下:1
2
3. filename # 点号与文件名中间有一个空格
或
source filename
实例
test1.sh
内容如下:1
2
3
url="http://www.baidu.com"
test2.sh
内容如下:1
2
3
4
. ./test1.sh # 或者 source ./test1.sh
echo "百度地址: $url"
其他
遍历命令结果
字段分隔符(Internal Field Separator, IFS
)是shell脚本中的一个重要概念, 处理文本数据的时候非常的有用, 是把单个数据流划分成不同数据元素的定界符. 系统环境默认的IFS是空白字符(换行符, 制表符或者空格)1
2
3
4
5
6
7
8
9$ jps -l
88483 ailegal-case.jar
85666 ailegal-center.jar
85797 ailegal-gateway.jar
pros=($(jps -l))
for pro in ${pros[@]}; do
echo $pro
done
输出:1
2
3
4
5
688483
ailegal-case.jar
85666
ailegal-center.jar
85797
ailegal-gateway.jar
如果想以换行符作为分隔符, 则可以这么做:
在Bash 4.0(bash -version
)之前:1
2
3
4
5
6
7
8
9ls -l | while read x; do echo $x; done
#或者
(IFS='
'
for x in `ls -l`; do echo $x; done)
#或者
while read x; do echo $x; done << EOF
$(ls -l)
EOF
如果是在函数内, 可以使用local
命令, 避免全局性的修改IFS1
2
3
4
5
6
7
8
9
10
test() {
local IFS=$'\n'
local lines=$(ls -l)
for line in $lines; do
echo $line
done
}
test
4.0以后可以使用mapfile
:1
2
3
4mapfile -t files < <(ls -l)
for file in "${files[@]}"; do
echo $file
done
生成随机数
1 | # 生成1个, 范围2000 ~ 6500 |
进程休眠sleep
1 | sleep 0.5 |