BASH快速入门手册
来源:互联网 发布:plc编程题目 编辑:程序博客网 时间:2024/05/01 00:38
转载地址:https://laoyur.com/?p=638
精心整理之作,转载请注明出处
本文目的:bash速查,快速上手。
目录
- 执行bash脚本
- 单双引号
- 首行
- 分号
- 注释行
- 空行
- 变量
- 变量声明
- 变量赋值
- 变量类型
- 变量作用域
- 引用变量
- 常用保留变量
- 字符串操作
- 整数运算
- 条件控制
- 判断语句
- 循环控制
- 通配符
- 数组
- 函数
- 获取用户输入
- export
- set & env
- exit
- 执行bash脚本
1
bash
xxx.sh
#执行xxx.sh文件
2
bash
-c
command
#以字符串方式直接执行。-c 的c代表command。如果command有参数(即有空格),需要用引号包裹。
可以在执行脚本前预先设置变量:
1
VAR1=
"hehe"
VAR2=
"heihei"
bash
-c
'echo $VAR1; echo $VAR2'
变量VAR1和VAR2的作用域只在该条语句中有效,不会污染当前shell。
另外,上面的这个例子中,单引号不能换成双引号,否则无法输出hehe、heihei,原因是啥?请继续看下文。
- 单引号 VS 双引号
单引号中的字符串不进行转义,原样输出;双引号中的内容会被转义。
例:echo ‘$HELLO’,输出 $HELLO。echo “$HELLO”,输出 world(假设$HELLO=world)。
回到上面那个例子,单引号使得$VAR1 和 $VAR2 原样传给bash -c 命令,从而获得了正确结果。
如果单引号换成双引号,则意思是输出当前shell中的$VAR1、$VAR2变量的值。而当前shell中有没有值是无可预料的,也就无法输出hehe、heihei了(再次提醒,VAR1=”hehe” VAR2=”heihei”的作用域不在当前shell中)。
- 首行
一般规范的shell脚本,首行都是:
1
#!/bin/bash
如果你的默认shell就是bash,或者你使用 bash xxx.sh方式打开的话,这行可以省略。
但如果别人来执行你的脚本,或者默认shell不是bash呢?
为了确保你的代码始终是用bash执行(通常你仅会为一种shell进行代码测试),加上这行很有必要。
额外的,注意一下 /etc/rc.local 文件的首行,你会发现长这样:
1
#!/bin/sh -e
多了个 -e 参数,表示一旦某条命令执行出错(返回值不为0),立即退出该脚本。
也可以使用 set -e 来达到同样的目的。下文会有关于 set 的更多详情介绍。
- 分号
通常一行只写一个语句,此时分号可以省略。但如果需要在一行中写多个语句,分号必须写。
例:
1
if [ 2 -eq 2 ]; then echo =; else echo !=; fi
- 注释行
使用井号 #
- 空行,no-op line
使用冒号 :
- 变量声明
使用declare(或typeset,两者完全等价。同时typeset也被zsh所支持)进行变量声明:
1
declare
STRING_VAL
#声明一个字符串变量
2
declare
-r READONLY_VAL
#声明只读变量,也可以写作 readonly READONLY_VAL
3
declare
-i INTEGER1
#声明整型变量
4
declare
-a ARRAY1
#声明数组变量
5
declare
-f
#打印出所有function
6
declare
-f FUNC_NAME
#打印出指定名称的function
7
declare
-x VAR_TO_EXPORT
#声明导出变量。跟使用export命令效果一样。
8
declare
-i -r ABC=2
#在声明变量类型的时候可以直接赋值
readonly的变量如果被导出到子shell,子shell拿到的拷贝将会失去readonly属性。
- 变量赋值
例:FILE_NAME=’abc.txt’
变量名不能使用保留字符,等号两侧不能有空格(否则会被认为是一个shell命令,而非赋值)。
被赋值的变量可以从未被声明。从未被声明过的变量默认是字符串类型。
1
declare
A=123
# 声明一个字符串变量A,并赋值为"123"
用字符串对一个整型变量进行赋值时,不会报错,但结果却是不可预料的。也就是说赋值操作不会改变变量被声明时指定的类型。例:
1
declare
-i NUMBER
2
NUMBER=abc
3
echo
$NUMBER
#输出 0
- 变量类型
没有用declare -i 声明为整形的变量,统统是字符串变量。
当然,即便是字符串变量,在整数运算时还是会被解释成整数。
- 变量作用域
当省略declare时,不管位于函数外还是函数内,变量的作用域为程序结束;
当在函数内部使用declare时,作用域为函数结束;
当在函数外部使用declare时,作用域为程序结束。
另外,在函数内,declare还有个别名,叫local,用这货能减少歧义。
所以,local也能使用declare的参数。
例:
1
function
func {
2
local
-i HELLO=123
3
HELLO+=1
4
echo
$HELLO
#输出124
5
}
- 引用变量
使用$符号加变量名进行变量引用。
例:FILE_NAME1=$FILE_NAME
标准的写法是${FILE_NAME},简写时可以省略花括号,但某些会引起歧义的地方,还是得用标准写法。比如引用数组变量(下文对数组有详述)。
- 常用的保留变量
$HOME:当前用户的根目录路径
$PATH:PATH环境变量
$PWD:当前工作路径
$0,$1,$2,…:第0个参数(shell脚本自身),第1个参数……
$#:参数的个数(不包括$0)
$@:获取本脚本程序/函数所有传入参数。
$*:同$@。但用双引号包裹后意义不同,$@、”$@”、$* 展开为原始参数,”$*”展开为一个字符串,内容为原始参数。
以下为示例代码:
01
function
showArgsCount {
02
03
echo
"args count:$#"
04
05
}
06
07
function
passArgs {
08
09
showArgsCount
"$*\n"
10
11
}
12
13
function
passArgs2 {
14
15
showArgsCount
"$@\n"
16
17
}
18
19
20
passArgs a b c
21
passArgs2 a b c
输出结果为:
1
args count:1
2
args count:3
$?:获取最近一次执行的脚本、程序或函数的返回值。正常为0,非0为错误。
$$:该脚本程序的进程号
$RANDOM:1-65536之间的整数
- 字符串操作
详情请点击:http://tldp.org/LDP/abs/html/string-manipulation.html
这里只记录几个常用的用法。
1
STR=abcdefg
2
POS=2
3
LEN=3
4
echo
${
#STR} # 输出7,$STR变量的strlen();
5
echo
${STR:2}
# 输出cdefg,从position 2处开始取substring
6
echo
${STR:2:3}
# 输出cde,从position 2处开始取长度为3的substring
7
echo
${STR:$POS:$LEN}
#输出cde,position和length都可以是变量
8
echo
${@:2}
#从此shell脚本传入args中取substring,@可以换成*
${string#substring}
从string中删除一个最短匹配,从开头往后匹配。#换成%,表示从结尾往前匹配。
${string##substring}
从string中删除一个最长匹配,从开头往后匹配。##换成%%,表示从结尾往前匹配。
例:
01
stringZ=abcABC123ABCabc
02
# |----| shortest
03
# |----------| longest
04
05
echo
${stringZ
#a*C} # 123ABCabc
06
# Strip out shortest match between 'a' and 'C'.
07
08
echo
${stringZ
##a*C} # abc
09
# Strip out longest match between 'a' and 'C'.
10
11
12
13
# You can parameterize the substrings.
14
15
X=
'a*C'
16
17
echo
${stringZ
#$X} # 123ABCabc
18
echo
${stringZ
##$X} # abc
19
# As above.
${string/substring/replacement}
将string中的第一个substring替换为replacement
${string//substring/replacement}
将string中的所有substring替换为replacement
${string/#substring/replacement}
如果string以substring开头,则把substring替换为replacement
${string/%substring/replacement}
如果string以substring结尾,则把substring替换为replacement
- 整数运算
首先可以使用let或expr进行整数运算,运算符支持 + – * / %
例:
1
NUM=12
2
let
NUM=$NUM+1
3
echo
$NUM
输出13。或者用expr来做:
1
NUM=12
2
NUM=`
expr
$NUM + 1`
3
echo
$NUM
两者等价。需要注意的是,let方式+两侧不能留空格,要留空格的话,需要把整段用引号包裹;而expr方式中,+号左右必须要留空格。所以结论是:let和expr都挺难用的。不过别急,还有另一种方式:
(( … )) 方式。例:
1
a=1
2
b=2
3
(( c=a+b ))
4
echo
$c
结果会输出3。
(( ))中的操作都会被处理成整数运算,由于不会被解释成字符串,因此引号和变量前的$符号都是不强制的。
此外,还支持 +=、-=、*=、/=、%=、>、< 等操作符,操作符左右的空格也是想加就加,怎么样,跟高级语言一样爽歪歪吧。
另外值得一提的是,$(( … ))才是这货的标准形式(POSIX标准)。
bash不支持浮点运算,如果上面的let例子中,NUM=12.1,那+1运算就会报错。实在想处理浮点数的话,需要借助外部命令:dc、awk或者bc。
猛击此链接查看更多关于整数运算的资料:
http://mywiki.wooledge.org/ArithmeticExpression
- 条件控制
先讲最基本的if – fi 语句。基本语法:
1
if
condition;
then
2
echo
hehe
3
echo
haha
4
else
5
echo
haha
6
echo
hehe
7
fi
1
if
condition;
then
2
:
3
elif
condition;
then
4
:
5
else
6
:
7
fi
如果then/else分支不需要写代码,则用冒号 : 来占位
condition表示一个判断语句。
然后讲讲case – esac(很明显,case倒着写就是esac)语句。
这货类似于switch case。
基本语法:
1
case
$val
in
2
val1)
command
;;
#分支1
3
val2 | val3)
command
;;
#分支2或3
4
*)
command
;;
#default
5
esac
- 判断语句
判断语句的返回值是true or false。
字符串判断:
1
[ $VAR1 = $VAR2 ]
#两个字符串是否相等。另外,!= 表示不相等,> < 分别表示 大于小于。
2
[ -z $VAR ]
#是否为空串(未定义的变量也属于空串)
3
[ $VAR ]
#是否不为空串
文件判断:
1
[ -e $FILE ]
#文件是否存在
2
[ -f $PATH ]
#是否是普通文件(非dir或symbol link之类)
3
[ -d $PATH ]
#是否是目录
4
[ -s $FILE ]
#文件大小不为0字节
5
[ -r $FILE ]
#文件对当前用户可读。相应的,还有 -w 可写、-x 可执行。如果$FILE是目录,-x表示是否可进入。
6
[ $FILE1 -nt $FILE2 ]
# $FILE1比$FILE2更新。-ot 表示更老。
整数判断:
1
[ $M -
eq
$N ]
# M == N
2
[ $M -
ne
$N ]
# M != N
3
[ $M -gt $N ]
# M > N
4
[ $M -lt $N ]
# M < N
5
[ $M -
ge
$N ]
# M >= N
6
[ $M -
le
$N ]
# M <= N
所有的判断,都可以在[ 后加 ! 表示非操作。
另外,中括号[ ] 可以换成 [[ ]](实际上推荐使用[[ ]],不过它并不是被所有shell所支持),两者的区别如下:
[ ]是“old test”,而 [[ ]] 是“new test”,可以看做 [ ] 的升级版。
[[ ]] 整数判断中同时支持 == 和 =,而[ ]只支持 =;
[[ ]] 可以防止含有空格的变量被分割,因此变量不用双引号包裹起来也是安全的。而[ ]中,变量不用双引号包裹时,如果它的值含有空格,就会引起语法错误(或意想不到的情况);
[[ ]] 文件判断时,通配符将不被bash展开,而是以字面符形式传递给 [[ ;//关于wildcard的详情,请参看下一段落。
[[ ]] 支持在一个[[ ]] 中直接使用 && || 来连接多个test,使用( )括号来指定与或的优先级。而使用 [ ] 的话,通常的做法都是用 && || 来连接多个 [] 块;
[[ ]] 支持使用 =~ 进行正则表达式测试。
更多详情,可以参考此链接:http://mywiki.wooledge.org/BashFAQ/031
- 循环控制
先讲最常用的for循环。
range based for loop:
1
for
i
in
1 2 3 4 5
#直接使用数组也是ok的,关于数组,请继续看下文。
2
do
3
echo
"Welcome $i times"
4
done
1
for
i
in
{1..5}
#指定 [start, end]区间。由于bash只支持整数,所以当然步进值为1咯
2
do
3
echo
"Welcome $i times"
4
done
1
for
i
in
{0..10..2}
#bash 4.0+ 可以自己指定步进值
2
do
3
echo
"Welcome $i times"
4
done
C语言风格的for loop:
1
MAX=5
2
for
(( c=1; c<=MAX; c++ ))
##变量名前可以不加$
3
do
4
echo
"Welcome $c times"
5
done
for循环中支持使用break和continue,跟C语言中一样。
接着是while循环:
1
while
condition
2
do
3
:
#blah blah
4
done
可以看到,就首行跟for有点区别,主体部分都是do … done,同样,它也支持break和continue。
- 通配符 wildcard
星号 asterisk *,表示0个或多个字符
问号 question mark ?,表示1个字符
通配符在判断语句中,行为比较复杂,我们没必要吹毛求疵弄清楚每一种情况,上文也提到用[[ ]]代替[ ],所以这里只讨论[[ ]]中通配符的规则。
作为字符串判断时:
wildcard在引号中,那它就是字面符,不作为通配符使用;
wildcard不在引号中,那它作为通配符使用。
作为文件判断时:
wildcard不管在不在引号中,都视作字面符,不会被bash展开。
所以:试图用*或?进行文件判断的做法,是不可行的。具体可以参考这个链接:
http://stackoverflow.com/questions/24615535/bash-check-if-file-exists-with-double-bracket-test-and-wildcards
注:什么叫做“被bash展开”?看一个例子就知道了:
假设写了如下的判断语句:
1
[ -f /*.txt ]
本意是想匹配是否有txt文件存在,如果/目录正好有且只有一个非隐藏的txt文件(或指向一个文件的symlink)存在,假设这个文件叫file.txt,则该语句被展开为 [ -f /file.txt ],同时它return true;如果/目录有多个txt存在,假设是file1.txt、file2.txt,那该语句被展开为 [ -f /file1.txt /file2.txt ],[ 命令将会报错说传递了太多参数过来。
- 数组
没错,bash支持一维数组。
1
ARRAY=(1 2 3 4)
#使用圆括号方式赋初值
2
echo
$ARRAY
# 输出第0个元素,即1。$ARRAY等价于${ARRAY},等价于${ARRAY[0]}
3
echo
${ARRAY[1]}
#输出第一个元素,即2。这里花括号不能省略
4
echo
${ARRAY[@]}
#输出所有元素,即1 2 3 4。类似的,@可以换成星号 *
5
echo
${
#ARRAY[@]} #输出元素个数,即4。同样,@可以换成星号 *
6
unset
ARRAY[1]
#删除第1个元素
7
ARRAY[1]=2
#再把2插入到索引1处,注意是插入,不是替换。
8
echo
${ARRAY[@]}
#元素依旧是 1 2 3 4
- bash函数
有两种书写形式:
1
function
foo {
2
echo
"hehe"
3
}
1
foo() {
2
echo
"hehe"
3
}
函数必须在调用之前定义。
函数可以用return语句返回整数(只能是整数)。如果没有return语句,或只写一个return,则返回的数值为最后一个语句的返回值(默认为0,表示成功)。为了防止不可预料的情况发生,建议return x语句不要省略。
调用处使用 $? 来获得返回值。
如何获得函数在stdout中输出的字符串——使用 $(…)形式调用函数。例:
1
test
() {
2
echo
"hehe"
3
return
123
4
}
5
output=$(
test
)
#或 `test`
6
result=$?
7
echo
$output
8
echo
$result
- 获取用户输入
1
echo
PLEASE ENTER SOMETHING
2
read
NAME
#用户输入的内容赋值给NAME变量
3
echo
$NAME
直接使用read会使得用户输入的内容同时被打印到屏幕,如果想输入的时候不显示内容(例如输入密码),使用:
1
read
-s NAME
- export
将某个变量导出(导出的只是一份拷贝,不是引用,因此子shell中对从父shell中继承的变量进行的修改,是无法反映到父shell中的。),使得可以在子shell中使用。前文在讲到readonly时提到,readonly类型的变量导出到子shell后,readonly属性将丧失,很明显,同时也会丧失“可导出”属性。
我们来理解一下/etc/rc.local 中经常写的 export PATH=$PATH:/home/someone/
以上命令的作用是,给PATH增加一个搜索路径后,重新导出,export是必须要加的。
开头提过,可以用declare -x 直接声明为导出变量;也可以随时用export将某个变量导出。
1
export
NUM=1
#变量赋值后导出
2
export
COUNT
3
COUNT=2
#先导出(不管有没有定义),再赋值
关于export,更多详情请参考:http://roclinux.cn/?p=1277
- set & env
set命令参数很多,不一一列举,这里只讲最常用的。
不带任何参数时,set 会输出当前shell所有的变量,包括所有函数以及从父shell导出的变量。
set -e,表示 exit if any sub command fails。
env不带任何参数时,会输出当前shell的环境变量,不包括函数。
env -i command,-i参数表示 Start with an empty environment, ignoring the inherited environment.
测试代码如下:
test.sh:
1
echo
"FUCK="
$FUCK
调用:
1
export
FUCK=fuck
#导出FUCK变量
2
bash
test
.sh
#输出FUCK=fuck
3
env
-i
bash
test
.sh
#输出FUCK=
- exit
exit命令的作用是退出当前shell,并返回错误码(不写exit时,返回最后一行代码的错误码。默认为0)。
其返回值也是使用 $? 来获取。
跟return类似,省略exit,或者只写exit而不带数值时,返回的是前一个命令的返回值。
所以为了避免一些不可预见的错误发生,exit语句最好不要省略。
- BASH快速入门手册
- BASH快速入门手册
- BASH SHELL快速入门
- Bash快速入门指南
- Linux Bash快速入门
- ubuntn快速入门手册
- Github快速入门手册
- valgrind快速入门手册
- Github快速入门手册
- MonetDB快速入门手册
- JNI快速入门手册
- Linux Bash Shell快速入门
- Linux Bash Shell快速入门
- Linux Bash Shell快速入门
- Linux Bash Shell快速入门
- Linux Bash Shell快速入门
- Linux Bash Shell快速入门
- 【Bash百宝箱】Makefile快速入门
- C#下的JS脚本引擎ReoScript
- mysql 分区与分表
- 字典树(trie树)、后缀树
- Oracle设置和修改system和scott的口令,并且如何连接到system和scott模式下
- java反射
- BASH快速入门手册
- 秒杀的问题
- mysql
- Linux 下的一个全新的性能测量和调式诊断工具 Systemtap, 第 3 部分: Systemtap
- 设计模式之结构型模式
- git shell
- 自定义adapter
- Lua数据结构 — Table(三)
- linux crontab usage