Shell学习
shell作为一种在Windows和linux下都可以快速使用,不用配置环境的语言,用起来是相当的方便,于是在学校考完试但是死活不放人的这段时间内对shell语言进行学习了解.
Hello World
1 | !/bin/bash |
#! 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell。
echo 命令用于向窗口输出文本。
shell变量
变量类型
- 局部变量 局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。
- 环境变量 所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量。
- shell变量 shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行
定义变量
- 变量名不加美元符号($,PHP语言中变量需要)
- 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。
- 中间不能有空格,可以使用下划线
_
- 不能使用标点符号。
- 不能使用bash里的关键字(可用help命令查看保留关键字)。
1 | str_hw="########" #可以正常的输出变量 |
用语句给变量赋值
1
2
3for file in `ls /etc`
or
for file in $(ls /etc)将 /etc 下目录的文件名循环出来
使用变量
用美元符号标记变量$
,可选用不用花括号包括{ }
【这样方便区分变量和语句,有没有都行】
1 | name_1="网名" |
显示结果:
1 | 网名 |
变量重用
定义之后的变量还可以被重新定义
只读变量
用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。
1 | readonly name_1 |
使用之后改变 变量的值会出现
1 | ./use_variable.sh: line 14: name_1: readonly variable |
删除变量
1 | unset variable_name |
变量被 删除后不能继续使用
字符串变量
单引号
中间有什么输出什么,不能使用转义字符,但是可以通过字符串拼接来实现。
双引号
可以使用转义字符来转义字符串中间的内容
1 | echo "hello my name is \"${two}\"" |
输出结果:hello my name is “world”
字符串拼接
单引号拼接
1 | name_2='wo shi '${two}'' |
这里注意,拼接的变量需要用一组单独的单引号引出,比如echo 'hello '$name' !'
双引号拼接
1 | name_2="hello, "${two}"1" |
同理,也是用一组单独的双引号引出
获取字符串长度
通过关键字#
获得
1 | str_1="abcdefg" |
变量为数组时,${#string}
等价于 ${#string[0]}
字符串切片
1 | echo ${str_1:0:3} |
这里的显示规则和其他语言基本一样,显示0,1,2字符
查找子字符串
1 | str_2="i am the best" |
数组变量
支持一维数组(不支持多维数组),并且没有限定数组的大小。
1 | 数组名=(值1 值2 ... 值n) |
可以不使用连续的下标,而且下标的范围没有限制。
用$array[index]
获得指定位置的元素内容
获取数组中的所有元素
使用@ 或 * 可以获取数组中的所有元素
基本运算
原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr 最常用。
expr
expr 是一款表达式计算工具,使用它能完成表达式的求值操作。
注意的是,他用反引号而不是单引号。
1 | val=`expr 2+2` |
需要注意的是,所有的运算符号都要和前后操作数通过空格隔开,还要中括号也要和变量隔开
1 | a=10 |
关系运算符
关系运算符只支持数字,不支持字符串,除非字符串的值是数字
运算符 | 说明 | 举例 |
---|---|---|
-eq | 检测两个数是否相等,相等返回 true。 | [ $a -eq $b ] 返回 false。 |
-ne | 检测两个数是否不相等,不相等返回 true。 | [ $a -ne $b ] 返回 true。 |
-gt | 检测左边的数是否大于右边的,如果是,则返回 true。 | [ $a -gt $b ] 返回 false。 |
-lt | 检测左边的数是否小于右边的,如果是,则返回 true。 | [ $a -lt $b ] 返回 true。 |
-ge | 检测左边的数是否大于等于右边的,如果是,则返回 true。 | [ $a -ge $b ] 返回 false。 |
-le | 检测左边的数是否小于等于右边的,如果是,则返回 true。 | [ $a -le $b ] 返回 true。 |
1 | a=10 |
这里看到判断结构
1 | if 条件表达式 |
逻辑运算符
运算符 | 说明 | 举例 | ||||
---|---|---|---|---|---|---|
&& | 逻辑的 AND | [[ $a -lt 100 && $b -gt 100 ]] 返回 false | ||||
\ | \ | 逻辑的 OR | [[ $a -lt 100 \ | \ | $b -gt 100 ]] 返回 true |
1 | a=10 |
- command1 && command2 #命令1执行成功后,命令2才执行
- command1 || command2 #命令1执行失败后,命令2才执行
字符串运算符
运算符 | 说明 | 举例 |
---|---|---|
= | 检测两个字符串是否相等,相等返回 true。 | [ $a = $b ] 返回 false。 |
!= | 检测两个字符串是否不相等,不相等返回 true。 | [ $a != $b ] 返回 true。 |
-z | 检测字符串长度是否为0,为0返回 true。 | [ -z $a ] 返回 false。 |
-n | 检测字符串长度是否不为 0,不为 0 返回 true。 | [ -n “$a” ] 返回 true。 |
$ | 检测字符串是否不为空,不为空返回 true。 | [ $a ] 返回 true。 |
1 | a="abcd" |
文件测试运算符
用于检测 Unix 文件的各种属性。
操作符 | 说明 | 举例 |
---|---|---|
-b file | 检测文件是否是块设备文件,如果是,则返回 true。 | [ -b $file ] 返回 false。 |
-c file | 检测文件是否是字符设备文件,如果是,则返回 true。 | [ -c $file ] 返回 false。 |
-d file | 检测文件是否是目录,如果是,则返回 true。 | [ -d $file ] 返回 false。 |
-f file | 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。 | [ -f $file ] 返回 true。 |
-g file | 检测文件是否设置了 SGID 位,如果是,则返回 true。 | [ -g $file ] 返回 false。 |
-k file | 检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。 | [ -k $file ] 返回 false。 |
-p file | 检测文件是否是有名管道,如果是,则返回 true。 | [ -p $file ] 返回 false。 |
-u file | 检测文件是否设置了 SUID 位,如果是,则返回 true。 | [ -u $file ] 返回 false。 |
-r file | 检测文件是否可读,如果是,则返回 true。 | [ -r $file ] 返回 true。 |
-w file | 检测文件是否可写,如果是,则返回 true。 | [ -w $file ] 返回 true。 |
-x file | 检测文件是否可执行,如果是,则返回 true。 | [ -x $file ] 返回 true。 |
-s file | 检测文件是否为空(文件大小是否大于0),不为空返回 true。 | [ -s $file ] 返回 true。 |
-e file | 检测文件(包括目录)是否存在,如果是,则返回 true。 | [ -e $file ] 返回 true。 |
其他检查符:
- -S: 判断某文件是否 socket。
- -L: 检测文件是否存在并且是一个符号链接。
1 | file="~/Shell/test_file" |
检测文件是否存在并且是否是一个符号链接
1 | !/bin/bash |
echo命令
普通字符
带不带引号,带什么引号都行
转义字符
echo -e "content"
变量
1 | read name |
输出不换行
1 | !/bin/bash |
printf命令
1 | !/bin/bash |
常用转义序列
\a | 警告字符,通常为ASCII的BEL字符 |
---|---|
\b | 后退 |
\c | 抑制(不显示)输出结果中任何结尾的换行字符(只在%b格式指示符控制下的参数字符串中有效),而且,任何留在参数里的字符、任何接下来的参数以及任何留在格式字符串中的字符,都被忽略 |
\f | 换页(formfeed) |
\n | 换行 |
\r | 回车(Carriage return) |
\t | 水平制表符 |
\v | 垂直制表符 |
\ | 一个字面上的反斜杠字符 |
\ddd | 表示1到3位数八进制值的字符。仅在格式字符串中有效 |
\0ddd | 表示1到3位的八进制值字符 |
流程控制
判断
如果 else 分支没有语句执行,就不要写这个 else。
1 | if condition |
精简写法,注意分号
1 | if [ $(ps -ef | grep -c "ssh") -gt 1 ]; then echo "true"; fi |
多重else
1 | if condition1 |
循环
for循环
1 | or var in item1 item2 ... itemN |
精简写法,注意分号
1 | for var in item1 item2 ... itemN; do command1; command2… done; |
while循环
while 循环用于不断执行一系列命令,也用于从输入文件中读取数据。其语法格式为:
1 | while condition |
比如
1 | !/bin/bash |
无限循环
无限循环语法格式:
1 | while : |
或者
1 | while true |
或者
1 | for (( ; ; )) |
until循环
until 循环执行一系列命令直至条件为 true 时停止。
until 循环与 while 循环在处理方式上刚好相反。
一般 while 循环优于 until 循环,但在某些时候—也只是极少数情况下,until 循环更加有用。
1 | until condition |
1 | int=0 |
case_esac
多分支选择结构,每个 case 分支用右圆括号开始,用两个分号 ;; 表示 break,即执行结束,跳出整个 case … esac 语句,esac(就是 case 反过来)作为结束标记。
第一种,匹配字符串
1 | !/bin/bash |
第二中,匹配数字
1 | !/bin/bash |
最后的*)
可以看作是default,当没有合适的匹配时执行。
跳出循环
break
break命令允许跳出所有循环(终止执行后面的所有循环)
1 | !/bin/bash |
执行到break之后,不仅仅跳出了case,还跳出了外面的while循环。
continue
continue命令与break命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环。
1 | !/bin/bash |
这里的实际效果看起来和直接注释掉continue之后没有什么区别。
函数
一般格式
1 | [ function ] funname [()] |
- 可以带function fun() 定义,也可以直接fun() 定义,不带任何参数。
- 参数返回,可以显式加:return 返回;不加,将以最后一条命令运行结果,作为返回值。 return后跟数值n(0-255
简单函数
1 | !/bin/bash |
返回值函数
调用函数的返回值用$?
1 | !/bin/bash |
参数函数
在函数体内部,通过 $n 的形式来获取参数的值,例如,$1表示第一个参数,$2表示第二个参数,而不是通过在函数的括号中指定参数。
1 | !/bin/bash |
另外,还有几个特殊字符用来处理参数:
参数处理 | 说明 |
---|---|
$# | 传递到脚本或函数的参数个数 |
$* | 以一个单字符串显示所有向脚本传递的参数 |
$$ | 脚本运行的当前进程ID号 |
$! | 后台运行的最后一个进程的ID号 |
$@ | 与$*相同,但是使用时加引号,并在引号中返回每个参数。 |
$- | 显示Shell使用的当前选项,与set命令功能相同。 |
$? | 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。 |
Shell 输入/输出重定向
重定向命令列表如下:
命令 | 说明 |
---|---|
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 | echo `ifconfig` > ipconfig |
得到文件ipconfig,其中包含了命令的回显内容
1 | ubuntu@VM-20-17-ubuntu:~/Shell/redirect$ cat ipconfig |
这里会覆盖文件之前的内容
输入重定向
和输出重定向相反
重定向是什么
一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件:
- 标准输入文件: stdin的文件描述符是 0 , Unix程序默认从标准输入读取数据’
- 标准输出文件: stdout的描述符是 1 , Unix程序默认向stdout输出数据
- 标准错误文件: stderr的描述符是 2 , Unix会将错误信息写到stderr中去.
这里在angr的dumps时也会涉及
- 如果希望 stderr 重定向到 file,可以这样写:
1 | $ command 2>file |
- 如果希望 stderr 追加到 file 文件末尾,可以这样写:
1 | $ command 2>>file |
- 如果希望将 stdout 和 stderr 合并后重定向到 file,可以这样写:
1 | $ command > file 2>&1 |
- 如果希望对 stdin 和 stdout 都重定向,可以这样写:
1 | command < file1 >file2 |
command 命令将 stdin 重定向到 file1,将 stdout 重定向到 file2。
Here Document
Here Document 是 Shell 中的一种特殊的重定向方式,用来将输入重定向到一个交互式 Shell 脚本或程序。
/dev/null 文件
希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null:
- /dev/null 是一个特殊的文件,写入到它的内容都会被丢弃;
- 尝试从该文件读取内容,那么什么也读不到;
- 命令的输出重定向到它,会起到”禁止输出”的效果
因此可以用他来屏蔽stderr和stdout
方式如下:
1 | command > /dev/null 2>&1 |
文件包含
Shell 也可以包含外部脚本
1 | . filename # 注意点号(.)和文件名中间有一空格 |
可以做到跨文件使用变量
1 | shell 1 |
在命令. ./test1.sh
中, .
起到了引用文件的作用, ./
是unix中正常的寻找文件的梦里,不然就回去根目录里找这个文件,而不是当前目录
一些补充
命令执行
一些命令可以用echo通过加反引号的方式执行,但是有些命令,比如
1 | apt -y install %%% |
就直接写在shell文件里就可以,不需要用echo去执行,否则会出问题.
重定向
在进行换源的时候
1 | . ./sources.sh |
这里的echo不用加-e
虽然文本中有\n
但是在写入文件的时候会自动转义,加-e
会把e也写进行.