运行Shell脚本
Shell脚本可以直接执行Shell命令,例如:
1
2
3
| echo Hello, world!
date
ls -l $HOME
|
为了运行Shell脚本,将上面的代码保存到文件test.sh,并在执行以下命令
另一种方式是在脚本开头添加一行#!/bin/bash
,之后执行以下命令
1
2
| chmod +x test.sh
./test.sh
|
第一行命令给脚本添加可执行权限(只需执行一次),第二行中的./
表示在当前目录中查找可执行文件。
退出脚本
状态码默认为0。
输入与输出
1
2
3
| echo "What's your name?"
read name
echo "Hello, $name!"
|
1
2
3
4
| $ bash test.sh
What's your name?
Alice
Hello, Alice!
|
变量和字符串
变量赋值:
注意等号前后不能有空格。
引用变量:$var
或${var}
1
2
3
4
| echo "str="$str
echo "a\"bc[$str]d\$ef\\g"
echo 'a\"bc[$str]d\$ef\\g'
echo "undefined="$undefined
|
输出如下:
1
2
3
4
| str=Hello, world!
a"bc[Hello, world!]d$ef\g
a\"bc[$str]d\$ef\\g
undefined=
|
获取命令输出
可以使用反引号或$()
获取其他命令的标准输出:
1
2
3
4
5
6
| path=`pwd`
echo $path
path1="`pwd`\include"
path2='`pwd`\include'
echo "path1=$path1"
echo "path2=$path2"
|
输出如下:
1
2
3
| /home/zzy
path1=/home/zzy/include
path2=`pwd`/include
|
语句
if语句
语法:
1
2
3
4
5
6
7
| if cond; then
cmd_list;
[elif cond; then
cmd_list;]
[else
cmd_list;]
fi
|
cond
为测试命令,返回值为0表示真,非0表示假。
测试命令:test
或[
,条件为真则返回0,否则返回1。
逻辑运算符
表达式 | 含义 |
---|
!expr | 非 |
( expr ) | 括号 |
expr1 -a expr2 | 与 |
expr1 -o expr2 | 或 |
整数比较
表达式 | 含义 |
---|
a -eq b | a等于b |
a -ne b | a不等于b |
a -lt b | a小于b |
a -le b | a小于等于b |
a -gt b | a大于b |
a -ge b | a大于等于b |
字符串比较
表达式 | 含义 |
---|
str1 = str2 或str1 == str2 | 字符串相等 |
str1 != str2 | 字符串不相等 |
str1 < str2 | str1按字典序小于str2 |
str1 > str2 | str1按字典序大于str2 |
-z str | 字符串为空(未定义不是空) |
-n str 或str | 字符串非空 |
注意:<
和>
需用\
转义,否则被认为是重定向符号。
文件判断
表达式 | 含义 |
---|
-f file | 判断文件是否存在 |
-d file | 判断目录是否存在 |
-r file | 判断文件是可读 |
-w file | 判断文件是可写 |
-x file | 判断文件是可执行 |
例如:
1
2
3
4
5
6
7
8
9
10
11
| if [ -f ./a.txt ]; then
echo "`pwd`/a.txt存在"
n=`cat ./a.txt | wc -l`
if [ $n -gt 10 ]; then
echo "内容大于10行"
else
echo "内容小于等于10行"
fi
else
echo "`pwd`/a.txt不存在"
fi
|
组合命令
表达式 | 含义 |
---|
cmd1 && cmd2 | 当且仅当cmd1返回值为0时才执行cmd2 |
cmd1 || cmd2 | 当且仅当cmd1返回值为非0时才执行cmd2 |
组合命令的返回值是最后执行的命令的返回值。
例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| echo "请输入成绩:"
read grade
if [ $grade -gt 100 -o $grade -lt 0 ]; then
echo "请输入0~100之间的数"
else
if [ $grade -ge 90 ]; then
echo "Excellent"
elif [ $grade -ge 80 -a $grade -le 89 ]; then
echo "Good"
elif [ $grade -ge 70 ] && [ $grade -le 79 ]; then
echo "Middle"
elif [ $grade -ge 60 ] && [ $grade -le 69 ]; then
echo "Passing"
else
echo "Bad"
fi
fi
|
简写形式
表达式 | 含义 |
---|
[ cond ] && cmd | if-then简写形式 |
[ cond ] && cmd1 || cmd2 | if-then-else简写形式 |
例如:
1
| [ `whoami` = "alice" ] && echo "你是alice" || echo "你不是alice"
|
case语句
语法:
1
2
3
4
5
6
| case expr in
pattern|pattern...)
cmd_list
;;
...
esac
|
例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| echo -n "请输入动物名称:"
read animal
echo -n "The $animal has "
case $animal in
"horse" | "dog" | "cat")
echo -n "four"
;;
"man" | "kangaroo")
echo -n "two"
;;
*)
echo -n "an unknown number of"
;;
esac
echo " legs."
|
while语句
语法:
1
2
3
| while cond; do
cmd_list;
done
|
当测试命令cond的返回值为0时循环执行语句。例如:
1
2
3
4
5
6
7
8
| i=0
while [ $i -lt 10 ]; do
echo -n "$i "
((i++))
# i=$(($i + 1))
# i=`expr $i + 1`
done
echo
|
输出如下:
until语句
语法:
1
2
3
| until cond; do
cmd_list;
done
|
当测试命令cond的返回值为非0时循环执行语句。例如:
1
2
3
4
5
6
| i=9
until [ $i -lt 0 ]; do
echo -n "$i "
i=$(($i - 1))
done
echo
|
输出如下:
for语句
简单for循环,类C语言
1
2
3
4
| for ((i=1;i<=10;++i)); do
echo -n "$i "
done
echo
|
遍历列表
1
2
3
4
| for i in 1 2 3 4 5; do
echo -n "$(expr $i \* $i) "
done
echo
|
使用seq命令生成列表
1
2
3
4
| for i in `seq 0 2 10`; do
echo -n "$i "
done
echo
|
使用反引号或$()
将命令的输出作为列表
1
2
3
| for file in `ls $HOME`; do
echo "$file"
done
|
将列表赋给变量
1
2
3
4
5
6
| list="alpha beta gamma"
list=$list" delta"
for i in $list; do
echo -n "$i "
done
echo
|
遍历命令行参数
- 各命令行参数:
$0
(脚本名)、$1
、$2
… - 参数个数:
$#
(不包括$0
) - 参数列表:
$*
或$@
(可用于for循环,不包括$0
)
例如:
1
2
3
4
5
| echo "命令行参数个数:$#"
echo "全部命令行参数:"
for arg in $*; do
echo "$arg"
done
|
1
2
3
4
5
6
| $ bash test.sh foo bar baz
命令行参数个数:3
全部命令行参数:
foo
bar
baz
|
读取文件
方法一:cat+while+read
1
2
3
4
5
6
| echo "Hello, world!" > test.txt
echo -e "A new Line.\nAnd another line." >> test.txt
cat test.txt | while read line; do
echo $line
done
rm test.txt
|
输出如下:
1
2
3
| Hello, world!
A new Line.
And another line.
|
方法二:for+cat
for-in语句默认的分隔符为空白符,由IFS环境变量指定
1
2
3
4
5
6
7
8
| echo -e "Hello, world!\nA new Line.\nAnd another line." > test.txt
OLD_IFS=$IFS
IFS=$'\n'
for line in $(cat test.txt); do
echo $line
done
IFS=$OLD_IFS
rm test.txt
|
数组
定义数组:用括号表示,元素用空格分隔
1
2
| num_arr=(0 1 2 3 4 5 6 7)
str_arr=("foo" "bar" "baz")
|
数组长度:${#arr[@]}
或${#arr[*]}
1
2
| echo "num_arr.length = "${#num_arr[@]}
echo "str_arr.length = "${#str_arr[*]}
|
1
2
| num_arr.length = 8
str_arr.length = 3
|
遍历数组:${arr[@]}
或${arr[*]}
1
2
3
4
| echo "num_arr = [ ${num_arr[@]} ]"
for x in ${num_arr[@]}; do
echo $x
done
|
1
2
3
4
5
6
7
8
9
| num_arr = [ 0 1 2 3 4 5 6 7 ]
0
1
2
3
4
5
6
7
|
分片访问:${arr[*/@]:start:length}
1
2
| echo "num_arr[2:4] = [ "${num_arr[@]:2:4}" ]"
echo "str_arr = [ "${str_arr[@]:0:${#str_arr[*]}}" ]"
|
1
2
| num_arr[2:4] = [ 2 3 4 5 ]
str_arr = [ foo bar baz ]
|
通过下标访问:${arr[index]}
1
2
3
4
5
6
| echo "num_arr[6] = "${num_arr[6]}
i=3
echo "num_arr[$i] = "${num_arr[$i]}
str_arr[1]="qux"
str_arr[10]="quux" # 如果下标越界则添加到尾部
echo "After setting: str_arr = [ "${str_arr[@]}" ]"
|
1
2
3
| num_arr[6] = 6
num_arr[3] = 3
After setting: str_arr = [ foo qux baz quux ]
|
删除元素:unset arr[index]
,删除整个数组:unset arr
1
2
| unset num_arr[3]
echo "After deleting num_arr[3]: num_arr = [ "${num_arr[@]}" ]"
|
1
| After deleting num_arr[3]: num_arr = [ 0 1 2 4 5 6 7 ]
|
模式替换:${arr[*/@]/pattern/replacement}
参考
GNU Bash参考手册