Shell基础概念
终端(Terminal) 指计算机操作系统中通过命令行界面(Command Line Interface,CLI)与用户进行交互的设备或程序。终端提供了一种文本界面,用户可以通过键盘输入命令,计算机会执行相应的操作并返回结果。
终端模拟器(Terminal emulator) 是指一种模拟终端的程序,可以在计算机上模拟出一个终端界面,提供命令行界面(CLI)供用户操作。终端模拟器可以在不同的操作系统中运行,例如在 Windows 操作系统中运行 PuTTY,可以连接到远程 Linux 系统上操作,这样用户就可以在 Windows 系统上使用 Linux 命令行界面进行操作。
Shell 是计算机操作系统中的一个程序,它是用户与操作系统内核交互的接口。Shell 接收用户输入的命令,并将其翻译成为操作系统内核可以理解的指令,操作系统内核执行指令后,将结果返回给 Shell,Shell 再将结果输出给用户。常见的 Shell 包括 Bash、Zsh、Fish 等。
Bash 是一种常见的 Shell,它是 GNU 项目中的一部分,被广泛应用于 Linux 和 macOS 等系统中。Bash 是一种功能强大的 Shell,它提供了很多实用的功能,例如自动补全、历史命令、别名等。
TTY 是 TeleTYpewriter 的缩写,是一种字符终端设备。在早期的计算机系统中,TTY 是一种物理设备,用户通过键盘输入命令,计算机将命令的结果输出到屏幕上。现在,TTY 通常指的是虚拟终端设备,例如在 Linux 操作系统中,用户可以通过 Ctrl+Alt+F1~F6 键切换到不同的虚拟终端界面,每个虚拟终端都对应一个 TTY 设备。
命令和语法
管道
在shell中,管道(Pipe)是一种非常有用的特性,它可以将一个命令的输出作为另一个命令的输入,从而使命令之间可以通过管道进行连接,形成一个管道链,进而实现更为复杂的操作。
具体地,管道是由一个竖杠符号“|”表示的,其作用是将命令的标准输出转发给后面的命令,后者将前者的输出作为自己的输入。例如,下面的命令将列出当前目录下的所有文件,并将其中以“.txt”为扩展名的文件的内容输出到grep命令中,后者将查找包含“hello”字符串的行:
ls | grep '.txt$' | xargs cat | grep 'hello'
在这个例子中,管道串联了四个命令,它们的作用依次为:
- ls:列出当前目录下的所有文件名;
- grep '.txt$':过滤出扩展名为“.txt”的文件名;
- xargs cat:将过滤出的文件名作为参数,依次输出它们的内容;
- grep 'hello':在输出的内容中查找包含“hello”字符串的行。
通过管道,我们可以将多个简单的命令组合成一个复杂的操作,实现更为高效、灵活的数据处理。
重定向
在shell中,重定向是将一个命令的输入或输出流连接到另一个位置的过程。具体来说,它是一种将命令的输入和输出重定向到不同的位置或文件的技术。
以下是几种常见的重定向方式:
- 标准输出重定向: “>”符号可以将命令的标准输出重定向到一个文件中,如将ls命令的输出写入一个文件:
ls > file.txt
- 标准错误输出重定向: “2>”符号可以将命令的标准错误输出重定向到一个文件中,如将错误信息写入一个文件:
command 2> error.txt
- 输入重定向: “<”符号可以将一个文件中的内容重定向到一个命令的标准输入中,如从一个文件中读取输入:
command < input.txt
- 输出追加: “>>”符号可以将命令的输出追加到一个文件的末尾,如将一个命令的输出追加到一个文件的末尾:
command >> file.txt
判断和分支
在shell中,判断命令主要指的是条件判断命令,可以根据指定条件的结果进行判断,从而执行不同的命令或操作。
常用的判断命令包括:
- if命令:用于判断某个条件是否成立,如果条件成立则执行指定的操作,否则执行其他操作。
例如,下面的代码中如果变量x的值等于0,则打印"变量x的值是0",否则打印"变量x的值不是0"。
x=0
if [ $x -eq 0 ]
then
echo "变量x的值是0"
else
echo "变量x的值不是0"
fi
- case命令:用于根据不同的条件执行不同的操作,类似于多个if语句的嵌套。
例如,下面的代码中如果变量x的值为1,则打印"变量x的值是1",如果变量x的值为2,则打印"变量x的值是2",否则打印"变量x的值不是1或2"。
x=1
case $x in
1)
echo "变量x的值是1"
;;
2)
echo "变量x的值是2"
;;
*)
echo "变量x的值不是1或2"
;;
esac
- test命令:用于测试某个条件是否成立,如果条件成立则返回0,否则返回1。
例如,下面的代码中如果变量x的值等于0,则返回0,否则返回1。
x=0
test $x -eq 0
echo $?
其中,$?表示上一个命令的返回值。
循环
Shell中有多种循环语句,包括for循环、while循环和until循环。这些循环的语法和使用方式类似,但是在循环条件和语法细节上有所不同。
下面是三种主要的循环语句的介绍:
- for循环
for循环语句通过枚举列表中的每个元素来迭代执行命令。列表可以是由任意字符分隔的多个值或者是一个通配符(例如,*.txt)。
下面是一个for循环的例子:
for i in 1 2 3 4 5
do
echo $i
done
该脚本将输出数字1到5,每个数字一行。
- while循环
while循环语句会重复执行一组命令,直到给定的条件不再为真。条件可以是任何命令或者是一个表达式。
下面是一个while循环的例子:
i=0
while [ $i -lt 5 ]
do
echo $i
i=$((i+1))
done
该脚本将输出数字0到4,每个数字一行。
- until循环
until循环语句会重复执行一组命令,直到给定的条件为真。条件可以是任何命令或者是一个表达式。
下面是一个until循环的例子:
i=0
until [ $i -ge 5 ]
do
echo $i
i=$((i+1))
done
该脚本将输出数字0到4,每个数字一行。
函数
下面是一个简单的函数,它接收两个参数,并输出它们的和:
sum () {
echo $(($1 + $2))
}
可以这样调用上面定义的函数:
sum 3 5
在shell中,函数的返回值是通过return
关键字来指定的。函数执行完毕后,返回值可以被调用该函数的上下文使用。需要注意的是,shell中函数返回值的取值范围是0~255,0表示成功,其他数字表示失败或者其他情况。
函数返回值可以通过以下方式进行使用:
-
直接调用函数并将返回值赋值给一个变量:
my_func() { return 123 } result=$(my_func) echo "Function returned: $result" # 输出: Function returned: 123
-
在命令行中调用函数并获取返回值:
my_func() { return 123 } my_func echo "Function returned: $?" # 输出: Function returned: 123
在函数中,可以使用return
返回任何数字。如果没有使用return
语句,那么函数的返回值将是最后一条命令的退出状态码。
注意事项
- shell自上而下执行,函数必须在使用前定义
- 函数获取变量和shell script类似,1、$2...获取
- 函数内的return仅仅表示函数的执行状态,不代表执行结果
- 返回结果一般使用echo、printf,在函数外使用$()等获取结果
- 如果没有return,函数状态是上一条命令的执行状态,存储在$?中
常用命令
- ls:列出目录中的文件和子目录。
- cd:改变当前工作目录。
- pwd:显示当前工作目录的路径。
- mkdir:创建一个新的目录。
- rm:删除文件或目录。
- cp:复制文件或目录。
- mv:移动或重命名文件或目录。
- touch:创建一个新文件或更新一个已有文件的修改时间。
- cat:显示文件内容或将多个文件合并为一个文件。
- grep:在文件中搜索指定的文本。
- find:在文件系统中搜索指定的文件。
- chmod:更改文件或目录的权限。
- chown:更改文件或目录的所有者。
- ps:列出当前正在运行的进程。
- top:显示系统的实时进程信息。
- kill:发送信号给指定的进程。
- tar:打包和压缩文件和目录。
- wget:从互联网上下载文件。
- ssh:通过网络连接到远程计算机。
- scp:通过网络复制文件到远程计算机。
执行过程和原理
执行过程
- 字符解析
- shell展开
- 重定向
- 执行命令
- 收集状态并返回
shell展开
Shell是一种解释性语言,当用户在终端中输入命令时,Shell会对命令进行展开和解释,最终执行命令并输出结果。在这个过程中,Shell使用了许多展开机制来扩展命令行。以下是Shell中常用的展开方式:
- 大括号展开(Brace Expansion):大括号展开是一种用于生成一系列字符串的展开方式。例如,
{a,b,c}
会展开为a b c
。大括号展开还支持嵌套,例如{a{1,2},b{3,4}}
会展开为a1 a2 b3 b4
。 - 波浪号展开(Tilde Expansion):波浪号展开用于扩展路径名中的
~
符号。~
会被扩展为用户的家目录,例如cd ~
会进入当前用户的家目录。 - 参数展开(Parameter Expansion):参数展开是一种用于扩展变量的展开方式。例如,
${var}
会被扩展为变量var
的值。参数展开还支持一些特殊的操作,例如${var:-default}
会被扩展为变量var
的值,如果var
未定义,则会使用默认值default
。 - 命令替换(Command Substitution):命令替换用于将命令的输出作为参数传递给另一个命令。命令替换可以使用反引号或
$()
符号来完成。例如,echo $(ls)
会将当前目录下的所有文件名输出到终端。 - 数学计算(Arithmetic Expansion):数学计算是一种将数学表达式求值的展开方式。数学计算可以使用
$((...))
符号来完成。例如,echo $((1+2))
会输出3
。 - 文件名展开(Filename Expansion):文件名展开是一种用于扩展通配符的展开方式。通配符可以用于匹配文件名中的字符。例如,
*.txt
会匹配当前目录下所有扩展名为.txt
的文件。