在本节中,我们将介绍Bash Terminal的一些基础语法。
一、文件目录相关
ls
i.e. list storage:显示当前目录下的文件与文件夹。pwd
i.e. print work directory:显示当前目录。cd
i.e. change directory:使用dir/dir/来切换相对目录(个人习惯使用./);使用/dir/dir来切换绝对目录。
1.1 pushd和popd
为了实现多个目录的相互跳转,这里使用一个目录堆来完成。当前的目录如下:
.
├── 01.sh
├── T1
├── T2
└── T3
使用dirs
可以查看该堆:
xjt@u16:~/mk/Bash$ dirs -p -v
0 ~/mk/Bash
1 ~/mk/Bash/T1
我已经向该堆添加了两个目录。下面我们使用pushd
可以向其中添加目录:
xjt@u16:~/mk/Bash$ pushd T2/
~/mk/Bash/T2 ~/mk/Bash ~/mk/Bash/T1
xjt@u16:~/mk/Bash/T2$ dirs -p -v
0 ~/mk/Bash/T2
1 ~/mk/Bash
2 ~/mk/Bash/T1
xjt@u16:~/mk/Bash/T2$
之后在使用pushd +n
来切换目录:
xjt@u16:~/mk/Bash/T2$ pushd +2
~/mk/Bash/T1 ~/mk/Bash/T2 ~/mk/Bash
xjt@u16:~/mk/Bash/T1$
出栈则使用popd
来完成:
xjt@u16:~/mk/Bash/T1$ popd +0
~/mk/Bash/T2 ~/mk/Bash
xjt@u16:~/mk/Bash/T2$ dirs -p -v
0 ~/mk/Bash/T2
1 ~/mk/Bash
1.2 文件与查找
- file:用于查看文件属性。
- locate:用于模糊查找文件。
1.3 创建文件夹与文件
- mkdir:创建文件夹。
- touch:创建文件。
1.4 拷贝与移动
- cp:拷贝。
- mv:移动。
二、文件编辑
2.1 concatenate
bash使用cat
来连接文件,我们有如下文件:
.
├── file1.txt
└── file2.txt
我们可以使用cat
来打印文件内容:
xjt@u16:~/mk/Bash$ cat file1.txt
hello
xjt@u16:~/mk/Bash$ cat file2.txt
world
同时能使用>>
来向文件中追加内容,使用>
来覆写:
xjt@u16:~/mk/Bash$ cat >> file1.txt
world
xjt@u16:~/mk/Bash$ cat file1.txt
hello
world
xjt@u16:~/mk/Bash$
当我们结束追加内容的时候,使用Ctrl+D
来结束命令。欲清空文件的内容则可以使用cat /dev/null > file1.txt
来完成,该命令是将一个文件的内容覆写到另外一个文件,追加则使用>
。
2.2 more & less
当我们想要查看文件内容的时候,可以使用more
或者less
来查看。使用more一次跳转多行,less则可以一行一行地跳转。两者均可以使用q
键退出。
2.3 文本编辑器
linux下的编辑器常用的有nano、vim、gedit。其中nano操作简单,在界面的下方有相应的提示;vim和gedit则没有,但是功能更加多样,比如同时处理多个文件等。
接下来,我们将介绍如何编写bash脚本。
三、开始
bash脚本与在终端中使用相同,直接使用命令即可,下面是一段简单的脚本,同时tree如下。
#! /bin/bash
ls
echo "Hello World"
# tree
# .
# └── run.sh
在第一行的#! /bin/bash
表示除此之外的所有#
引导的内容均为注释。值得注意的是,我们直接使用./run.sh
是无法直接运行的,我们要么使用bash run.sh
,要么给予它+x
的权限。例如:
xjt@u16:~/mk/Bash$ bash run.sh
run.sh
Hello World
xjt@u16:~/mk/Bash$ chmod +x run.sh
xjt@u16:~/mk/Bash$ ./run.sh
run.sh
Hello World
sh和bash有着相似的内容,但对于规则的兼容性不同。对于ubuntu来说,/bin/sh
指向/bin/bash
,但是也可以使用-posix
来指定其模式。
四、基本语法
4.1 if
下面是一段基础的逻辑判断:
Name="XJT"
if [ "$Name" == "XJT" ]
then
echo "Your name is XJT"
else
echo "Your name is not XJT"
fi
在上面的代码中,有几个需要注意的地方。一是变量赋值之间是不允许有空格,即Name="XJT"
,而不是Name = "XJT"
;二是if之后不使用()
,而是使用[]
,同时需要注意括号前后均有空格,即if [ $val ]
,而非if [$val]
。
接下来我们看一下一般变量的情况。
Num1=3
Num2=5
if [ $Num1 -gt $Num2 ]
then
echo "$Num1 is greater than $Num2"
else
echo "$Num1 is less than $Num2"
fi
接下来看对于文件的处理。
File="hello.txt"
if [ -f $File ]
then
echo "$File Exist"
else
echo "$File not Exist"
fi
# xjt@u16:~/mk/Bash$ tree
# .
# └── run.sh
# 0 directories, 1 file
# xjt@u16:~/mk/Bash$ ./run.sh
# hello.txt not Exist
# xjt@u16:~/mk/Bash$ touch hello.txt
# xjt@u16:~/mk/Bash$ tree
# .
# ├── hello.txt
# └── run.sh
# 0 directories, 2 files
# xjt@u16:~/mk/Bash$ ./run.sh
# hello.txt Exist
# xjt@u16:~/mk/Bash$
在上面的if
中,我们使用-f
来指定$File
为文件。同样的,其他的标签如下:
-d
,是目录-e
,文件存在,常用-f
代替。-f
,提供的字符串是文件。-g
,文件已有group id。-r
,可读。-s
,大小不为零-u
,已有user id。-w
,可写。-x
,可执行。
4.2 case
case与C中的switch相同,下面来看一下它是如何运作的。
read -p "Input y/yes or n/no: " Input
case $Input in
[yY] | [yY][eE][sS])
echo "yes!"
;;
[nN] | [nN][oO])
echo "no!"
;;
*)
echo "default output"
;;
esac
在上面的代码中,有几个需要注意的地方。一是在每一个分支的后面需要加上)
;二是每个分支结束需要加上;;
;三是最后的*
相当于其他语言中的default
。
4.3 for
for循环与python相似,下面是一个最基本的for循环。
Array="1 2 3 4 5"
for it in $Array
do
echo "$it"
done
下面来看一个对文件重命名的脚本:
txtFiles=$(ls *.txt)
att="new"
for file in $txtFiles
do
echo "Rename $file to $att-$file"
mv $file $att-$file
done
4.4 while
接下来看一下如何使用while来读取一个文件夹的内容。
Line=1
while read -r CURRENT_LINE
do
echo "$Line: $CURRENT_LINE"
((Line++))
done < "./file.txt"
4.5 function
下面是一个简单的Hello world函数。
function hello()
{
echo "Hello world"
}
hello
bash中含参函数和其他语言并不一样,其参数并不需要声明到()
中,来看一个例子:
function sum()
{
let ans=$1+$2
echo "Sum: $ans"
}
sum 5 6