shell 相关
通配符
- '*':匹配0个或者多个
- '?':匹配任意单个字符串
- ls -l file?.txt 这种情况下 file10.txt 就不会被匹配出来
- [list] :匹配list当中的任意单个字符串
- ls -l file[1-10].txt ---> file1.txt,file0.txt,逻辑:匹配单个字符串 file[1-1].txt file[0].txt
- ll file[1-2,10,11].txt ---> file0.txt file1.txt file2.txt 如果有,.txt也会匹配出来
- [!list]:匹配除list中的任意单个字符串
- {string1,string2} 匹配 string1 string2 或者更多字符串
- ll file{5..9}.txt ---> file5.txt,file6.txt,file7.txt,file8.txt,file9.txt
引号
- 双引号 :会把引号的内容当做整体来看待,允许通过$符号引用其他变量值
- 单引号:会把引号的内容当做整体来看待,禁止引用其他变量值,shell中特殊符号都被视为普通字符
- 反撇号:反撇号和$()一样,引号或括号里的命令会优先执行,如果存在嵌套,反撇号不能用
- echo $(date) ---> 2020年 5月 2日 星期六 12时10分27秒 CST
- echo "$(date)" ---> 2020年 5月 2日 星期六 12时10分44秒 CST
- echo '(date)
- echo "
date
" ---> 2020年 5月 2日 星期六 12时12分30秒 CST
变量
基本用法
➜ shell命令学习 A=hello # 定义
➜ shell命令学习 echo $A # $A 表示变量
hello
➜ shell命令学习 echo ${A} # ${A} 表示变量
hello
➜ shell命令学习 echo ${A:1:3} # 从第一个字符开始,截取三个
ell
➜ shell命令学习 unset A # 重置A,释放变量A
➜ shell命令学习 B=$(hostname) # 将命令的输出结果赋值给某个变量
➜ shell命令学习 echo $B
dingdeMacBook-Pro.local
变量名规则:区分大小写,不要有特殊字符,不能以数字开头,等号两边不能有任何空格
使用方式:{A}
-
类型声明:
- declare -i B=123 -i 将变量声明成整数
- declare -r C=hello -r 将变量声明为只读,不能再次修改,如果修改的话,会报错,可以exit结束这个变量,生命周期就会结束
- declare -x D=hello -x 将变量通过环境导出,与export一样
-
变量分类
本地变量,只对当前进程有效
-
环境变量,当前进程有效,并且能够被子进程调用
- env 查看当前用户的环境变量
- set 查看当前用户的所有变量(临时变量+环境变量) set|grep path
- export 变量名=变量值
-
全局变量,所有用户和进程都能调用,且继承,新建的用户也默认能调用
- ~/.bashrc 当前用户的bash信息,用户登录时读取。只是针对用户。一般用于定义别名,umask,函数等
- ~/.bash_profile 当前用户的环境变量,用户登录时读取。
- ~/.bash_logout 当前用户退出当前shell时最后读取
- /etc/profile 全局环境变量
- /etc/bashrc 全局bash信息,所有用户生效
- 读取顺序 /etc/profile ==> ~/.bash_profile ==> ~/.bashrc ==> /etc/bashrc ==> ~/.bash_logout
-
系统变量
命令 上一个命令或函数的返回码,0-正常 $0 当前执行的程序或者脚本名,一般在某个脚本中,获取自身文件名 $# 脚本后面接的参数的个数 $* 脚本后面所有的参数。每个变量参数之间以空格隔开 $@ 脚本后面所有的参数。参数是对立的,也是全部输出 9 脚本后面的位置参数,$1 表示第一个位置参数 {n} 扩展位置参数,第10个位置变量必须用{}大括号括起来(2位数字以上括起来) $$ 当前所在的进程的进程号 $! 后台运行的最后一个进程号 !$ 调用最后一条命令历史中的参数 $? 上一个命令或函数的返回码,0-正常
四则运算
表达式 | 示例 |
---|---|
$(()) | echo $((1 + 10)) ==> 11 |
$[] | echo $[1+10] ==> 11 |
expr | expr 1 + 10 ==> 11 这里需要有空格,不能用括号,乘法的话要加转义符 expr 2 * 10 |
let | n=2;let n=n+10;echo $n; let n=n**3 n的3次方 |
条件判断语句
语法
- test 条件表达式
- [ 条件表达式 ] 注意,[] 里面有空格
- [[ 条件表达式 ]] 支持正则表达式,注意,[] 里面有空格
- [ ! 条件表达式 ] 取返表达式
判断文件类型
判断参数 | 含义 |
---|---|
-e | 文件是否存在 |
-f | 文件是否存在并且是一个普通文件 |
-d | 文件是否存在并且是一个目录 |
-L | 文件是否存在并且是一个软连接文件 |
-r | 文件是否存在并且是一个可读的文件 |
-w | 文件是否存在并且是一个可写的文件 |
-x | 文件是否存在并且是一个可执行的文件 |
-O | 文件是否存在并且属于有效用户ID |
-G | 文件是否存在并且属有效用户组 |
-s | 文件是否存在并且是一个非空文件 |
file1 -nt file2 | 比较file1是否比file2新 |
file1 -ot file2 | 比较file1是否比file2旧 |
file1 -et file2 | 比较是否为同一个文件,或者用于判断硬连接是否指向一个inode |
判断字符串
判断参数 | 含义 |
---|---|
-z | 是否为空字符串,字符串长度为0则成立 |
-n | 是否为非空字符串,字符串长度不为0则成立 |
s1 = s2 | 字符串是否相等;注意等号两边有空格;[ "B" ] |
s1 != s2 | 字符串是否不相等;注意等号两边有空格; |
[ $sting ] | 字符串是为非空,和-n类似 |
判断整数
判断参数 | 含义 |
---|---|
-eq | 等于 |
-ne | 不等于 |
-gt | 大于 |
-ge | 大于等于 |
-lt | 小于 |
-le | 小于等于 |
多重条件判断
判断符号 | 含义 | 举例 |
---|---|---|
-a 和 && | 逻辑与 | [ 1 -eq 1 -a 1 -ne 0 ] [ 1 -eq 1 ] && [ 1 -ne 0 ] |
-o 和 || | 逻辑或 | [ 1 -eq 1 -o 1 -ne 0 ] [ 1 -eq 1 ] || [ 1 -ne 0 ] |
这里有个优先级的问题
[ $(id -u) -eq 0 ] && echo "is admin" || echo "is not admin"
上面的话,输出为 is not admin,&& 如果前面的条件不满足,就不会执行后面了,|| 如果前面的条件不满足,就会执行后面
类C风格的数值比较
在(( ))中 判断
(( 1==1 ));echo $?
(( 1<=2 ));echo $?
(( 2!=3 ));echo $?
注意点
[ ] 和 [[ ]],有什么区别?
A=
[ $A = hello ] # 这一行会报错
# 下面一行不会报错,我们写字符串判断的时候,可以这么写;
# 这里还要注意,$A不能使用单引号引起来
[ "$A" = "hello" ]
# 使用[[ ]] 也不会报错
[[ $A = hello ]]
# 下面这句话会报错
[ 1 -eq 1 && 1 -eq 0 ]
# 使用[[ ]]后,不会报错了
[[ 1 -eq 1 && 1 -eq 0 ]]
if语句
if []; then
命令
elif []; then
命令
else
命令
if
循环
for循环
for variable in {list}
do
command
done
# 使用可选列表
for i in a b c;do echo "$i";done
# 使用 seq
for i in $(seq 10); do echo $i ;done
# 使用 seq 从1开始,到10,每次加2
for i in $(seq 1 2 10); do echo $i ;done
# 类C风格
for (( i=0;i<5;i++ ));do echo $i;done
# 这种方式可以让用户通过参数的形式来自定义数量,for i in '"$@"'
for i;do echo $i;done
##########
for i in {1..5}
do
echo "$i"
done
并发执行:
{程序}& 表示将程序放到后台并执行,如果需要等待程序执行完毕再进行下面内容,需要加wait
for ((i=1;i<=100;i+=2 ))
do {
echo "hello"
}&
done
wait
echo "输出完毕"
while循环
while 表达式
do
command
done
# while true
i=1
while (($i<=5))
do
echo $i
let i++
done
until循环
until 表达式
do
command
done
# until false
i=1;
until (($i>5));
do
echo $i;
let i++;
done
随机数
# (0-32767)
echo $RANDOM
# 0-9的随机数,取余
echo $[$RANDOM%10]
# 100 - 999
echo $[$RANDOM%900+100]
shift
使位置参数向左移动,默认移动1位,可以使用 shift 2 移动两位
sum=0
# $# 参数列表
while [ $# -ne 0 ]
do
let sum=$sum+$1
# 将参数位置先左移动1位 此时 $1 取出来的值为当前的那个参数
shift
done
echo $sum
expect
expect 自动应答,tcl语言,例如远程登录,需要输入密码,expect就可以做到
数组
普通数组
一次赋予一个值
# 数组名[索引下标]=值
array[0]=v1
array[1]=v2
一次赋予多个值
# 数组名=(值1 值2 值3 ...) 空格隔开
array=(var1 var2 var3)
array1=(`cat /etc/passwd`) # 将文件中每一行赋值给array1数组
array2=(`ls /root`)
array3=(1 2 3 4 "hello world" [10]=linux)
数组读取
${数组名[元素下标]}
echo ${array1[0]} # 数组中的第0个元素
echo ${array1[*]} # 数组里的所有元素
echo ${array1[@]} # 数组里的所有元素
echo ${array1[*]:1:100} # 访问指定的元素;1代表下标从1的元素开始获取,100 代表后面获取几个元素
echo ${#array1[*]} # 获取数组中所有元素的个数
echo ${!array1[*]} # 获取数组元素的索引下标
关联数组
赋值
declare -A a_array1
a_array1[linux]=5
declare -A a_array2=(["hh"]="3" [kk]="4")
取值
echo ${a_array1[C]}
echo ${a_array1[*]} # 所有的value
echo ${!a_array1[*]} # 所有的key
case
case $1 in
start|S) # 如果是 start 或者是 S
echo "is start..." # 执行语句
;; # 两个分好,命令结束
stop|T)
echo "is stop..."
;;
*) # default 不满足上面的模式,执行*)下面的语句
echo "请输入些什么吧..."
esac # case 语句结束
函数
定义
函数名()
{
函数体
}
function 函数名()
{
函数体
}
return 的作用
- 结束一个函数
- return 默认返回最后一个命令状态值,也可以给定参数值,范围是0-256
- 如果没有return 命令,函数将返回最后一个指令的退出状态值
调用函数
source xxx.sh
# 直接使用方法名调用
hello
传参
hello()
{
echo "hello $1"
}
正则表达式
相关概念
- 元字符:值那些在正则表达式中具有特殊意义的专用字符,如 . * ?
- 前导字符:位于元字符前面的字符 abc*(c为前导字符)
元字符
元字符 | 功能 | 备注 |
---|---|---|
. | 匹配除类换行符意外的任意单个字符 | |
* | 前导字符 出现0次 或者多次 | |
.* | 任意长度字符 | abc.* |
^ | 行首(以...开头) | ^root |
$ | 行尾(以...结尾) | bash$ |
^$ | 空行 | |
[] | 匹配括号里任意单个字符或一组单个字符 | [abc] 包括a或者b或者c |
[^] | 匹配不包括括号里任一单个字符或一组单个字符 | [^abc] 不包括a或者b或者c |
^[] | 匹配以括号里任意单个字符或一组单个字符开头 | ^[abc] 以a或者b或者c开头 |
[] | 匹配不以括号里任意单个字符或一组单个字符开头 | |
\< | 取单词的头 | \<hel 以hel开头 |
\> | 取单词的尾 | |
\< \> | 精确匹配 | \<hello\> 精确匹配hello单词 |
\{n\} | 匹配前导字符 连续出现n次 | go\{2\},o连续出现2次 goo。[0-9]\{2\} 两位数字 |
\{n,\} | 匹配前导字符 至少出现n次 | go\{2,\},o至少出现2次 go,goo,gooo |
\{n,m\} | 匹配前导字符 出现n次到m次之间 | go\{2,4\},o出现2-4次 goo,gooo,gooo |
\( \) | 保存被匹配的字符 | |
\d | 匹配数字 (grep -P) | [0-9] |
\w | 匹配字母数字下划线 (grep -P) | [a-zA-Z0-9_] |
\s | 匹配空格、制表符、换页符 (grep -P) | [\t\r\n] |
扩展类正则
需要注意
- grep 需要用 -E 或者 egrep
- sed 需要加 -f
扩展元字符 | 功能 | 备注 |
---|---|---|
+ | 匹配一个或多个前导字符 | bo+ 匹配boo、bo |
? | 匹配零个或一个前导字符 | bo? 匹配bo、b |
| | 或 | a|b 匹配a或者b |
() | 组字符(看成整体) | (a|b)c:便是匹配ac或则bc |
{n} | 前导字符重复n次 | |
{n,} | 前导字符重复至少n次 | |
{n,m} | 前导字符重复n到m次 |
sed
常见的语法格式有两种。一种是命令行模式,另外一种是脚本模式
1、命令行模式(参考网址)
sed [option] '处理动作' 文件名
常用选项
选项 | 说明 | 备注 |
---|---|---|
-e | 进行多项(多次)编辑 | |
-n | 取消默认输出 | 不自动打印模式空间 |
-r | 使用扩展正则表达式 | |
-i | 原地编辑(修改源文件) | 慎用 |
-f | 指定sed脚本的文件名 |
常见处理动作
动作 | 说明 | 备注 |
---|---|---|
'p' | 打印 | |
'i' | 在指定行之前插入内容 | 类似vim里的大写O |
'a' | 在指定行之后插入内容 | 类似vim里的小写o |
'c' | 替换指定行所有内容 | |
'd' | 删除指定行 |
举个例子
sed -n 'p' pass.txt # 打印每一行
sed -n '2p' pass.txt # 打印第2行
sed -n '1,5p' pass.txt # 打印第1-5行
sed -n '$p' pass.txt # 打印最后一行
sed 'ihello' pass.txt # 在每一行插入hello
sed '2,3ihello' pass.txt # 在第2行和第3行前面插入 hello
sed '2,3ahello' pass.txt # 在第2行和第3行后面插入 hello
# 注意,mac系统中需要添加\n
sed "5i\\"$'\n'"helloworld" pass.txt
sed '5i\'$'\n''helloworld' pass.txt
# 替换
sed '2,5cChina' pass.txt
sed '2,5c\'$'\n''China' pass.txt # mac 中的操作
# 删除
sed '1d' pass.txt #删除第一行
sed '/^helloworld/d' pass.txt #删除正则匹配到的那一行
sed '/^#/d' pass.txt
sed -ne '/root/p' -ne '/root/=' pass.txt# 先找出root关键字的行,然后在打印包含root关键字的行号
sed -ne '1p;5p' pass.txt # 打印第1行和第5行
sed -e '/^#/d' -e '/^$/d' pass.txt # 删除#和空格的行
sed -r '/^#|^$/d' pass.txt # 删除#和空格的行
sed -i '1d' pass.txt #删除第一行,直接修改了文件
搜索替换
# sed 选项 's/搜索的内容/替换的内容/p' 需要处理的文件
sed -n 's/root/ROOT/gp' 1.txt # gp为全局替换
sed -n 's/^#//gp' 1.txt # 将行首的#替换为空格(去掉行首#)
sed -n '1,5s/^/#/p' pass.txt # 1-5行首添加 #
sed -n 's@/root@/ROOT/gp' 1.txt # 这样写也是可以的
其他动作
动作 | 说明 | 备注 |
---|---|---|
r | 从另外文件中读取内容 | |
w | 内容另存为 | |
& | 保存查找串以便在替换串中引用 | 类似vim里的小写o |
= | 打印行号 | |
! | 对所选行意外的所有行应用命令,放到行数之后 | |
q | 退出 |
sed '3r /etc/hosts/' 1.txt # 读取hosts文件到1.txt的第三行,如果不表明行号的话,则在1.txt文件中,每一行都会插入hosts文件的内容
sed '1,5w 11.txt' 1.txt # 将1.txt中的1-5行,写入11.txt文件中
sed -n 's/^sync/#&/gp' 1.txt # 在以sync开头的哪一行的行首添加#
sed -n '/root/=' 1.txt # 打印包含root关键字的行号
sed -n '$=' pass.txt # 打印最后一样的行号
sed -n '1,5!p' 1.txt # 打印不包含1-5行的所有内容
结合正则表达式
sed 选项 'sed命令或者正则表达式或者地址定位' 文件名
正则 | 说明 | 备注 |
---|---|---|
/key/ | 查询包含关键字的行 | sed -n '/root/p' 1.txt |
/key1/,/key2/ | 匹配包含两个关键字之间的行 | sed -n '/root/./mysql/p' 1.txt |
/key/,x | 从匹配关键字的行开始到文件的第x行之间的行(包含关键字所在的行) | sed -n '/^root/,7p' 1.txt |
x,/key/ | 从第x行开始到与关键字的匹配行之间的行 | |
x,y! | 不包含 x到y 行 | |
/key/! | 不包含关键字的行 | sed -n '/root/!p' 1.txt |
sed -nr '3,/^aa|^yy/p' # 打印从第三行到 以aa开头或者以yy开头 的行
脚本模式
# sed -f scripts.sh file # 使用脚本处理文件
# 脚本的第一行
#!/bin/sed -f
1,5d # 删除1-5行
s/root/hello/g # 将hello 替换成 hello
3i7777 # 在第三行添加 7777
注意:
- 脚本文件是一个sed的命令行清单 'commands'
- 在每行的末尾不能有任何空格、制表符(Tab) 或者饿其他文本
- 如果在一行中有多个命令,应该使用分号隔开
- 不需要且不可以使用引号做命令符
-
号开头的行为注释
AWK
1、简介
awk 主要是对文本和数据进行处理,他处理文本和数据的方式:逐行扫描,默认从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行想要的操作
2、使用方式
命令模式
1、语法结构
awk 选项 '命令部分' 文件名
# 引用shell变量需要使用双引号引起来
2、常用选项
- -F 定义字段分割符号,默认是空格
- -v 定义变量并赋值
3、命令部分
- 正则表达式,地址定位
'/root/{awk语句}' # sed中 '/root/p'
'NR=1,NR=5{awk语句}' # sed中 '1,5p'
'/^root/,/^root/{awk语句}' # sed中 '/^root/,/^ftp/p'
- {awk语句;awk语句2;...} 注意中间是分号
'{print $0;print $1}' # sed中 'p'
'NR=5{print $0}' # sed中 '5p'
# 注意:awk命令语句间用分号隔开
- BEGIN...END... 处理之前可以做些事情,处理之后可以做些事情
'BEGIN{awk语句};{处理中};END{awk语句}' # 拦截处理中的钩子
'BEGIN{awk语句};{处理中}'
'{处理中};END{awk语句}'
脚本模式
1、脚本编写
#!/bin/awk -f 定义魔法字符
# 下面是awk引号里的命令清单,不要用引号保护命令,多个命令用分号分割
BEGIN{FS=":"}
NR==1,NR==3{print $1"\t"$NF}
...
2、脚本执行
# 方法1
awk 选项 -f awk的脚本文件 要处理的文本文件
awk -f awk.sh fileName
sed -f sed.sh -i filename
# 方法2
./awk的脚本文件(或者绝对路径) 要处理的文本文件
./awk.sh filename
./sed.sh filename
3、awk内部相关变量
变量 | 变量说明 | 备注 |
---|---|---|
$0 | 当前处理行的所有记录 | |
2,n | 文件中每行以间隔符号分割的不同字段 | awk -F: '{print 2}' 1.txt |
NF | 当前记录的字段数(列数) | awk -F: '{print NF}' 1.txt |
$NF | 最后一列内容 | $(NF-1)表示倒数第二列 |
FNR/NR | 行号 | awk -F: '{print NR}' 1.txt |
FS | 定义间隔符 | BEGIN{FS=:};{print 3} |
OFS | 定义输出字段分割符,默认空格 | BEGIN{OFS=:};{print 3} |
RS | 输入记录分割符,默认换行 | BEGIN{RS="\t"};{print $0} |
ORS | 输出记录分隔符,默认换行 | |
FILENAME | 当前输入的文件名 |
相关命令举例
awk 'NR==1,NR==5{print $0}' 1.txt # 第一行到第五行
awk 'NR==1||NR==5||/root/{print $0}' 1.txt # 第一行或者第五行.或者包含root的行
awk 'NR>=1&&NR<=5{print $0}' 1.txt # 使用< 或 >
awk 'NR==1,NR==5;/^root/{print $0}' 1.txt # 这里是两个动作,满足/^root/的行会打印两次
awk -F: '/root/' 1.txt # 用:分割,包含root的行
awk -F: '/root/{print $0}' 1.txt # 和上面的等价
awk -F: '/^root/,NR==10{print $0}' 1.txt # 从以root开头的行匹配到第10行
awk -F: '/^root/,/^_lp/{print $1,$NF}' 1.txt # 用:分割,从 root开头的行到_lp开头的行,分割的字符的第一个和最后一个
awk 'BEGIN{FS=":";OFS="###"};/root/{print $1,$NF}' 1.txt # 以分号分割,输入内容以###拼接, 包含root的关键字,打印第1行和最后一行 root###/bin/sh
awk 'BEGIN{FS=":"};/root/{print $1"###"$NF}' 1.txt # 这句话和上面一样
awk 'BEGIN{FS=":"};{print "用户名:"$1",目录是"$NF}' 1.txt # 可以这样拼接
###################################################
date | awk '{print $1,$2,$4}' # 命令结果
4、使用进阶
1、printf 格式化输出
# %s 字符类型 %d 数值类型
# - 左对齐,默认右对齐
# 15 占15字符
# 默认不会再行尾自动换行,需要添加\n
awk -F: '{printf "%-15s %-15s \n",$1,$4}' 1.txt
2、变量定义
awk -F: -v NUM=3 '{print $NUM}' 1.txt # 变量名有$,此时是打印的第三个行
awk -F: -v NUM=3 '{print NUM}' 1.txt # 没有$ 此时打印的是变量
awk -v num=3 '{print num}' # 这样写,会等待输入文件名
awk -v num=3 'BEGIN {print num}' # 这样会打印变量
3、awk 中 BEGIN...END使用
- BEGIN 程序开始前执行
- END 所有文件处理完后执行
- 用法
'BEGIN{awk语句};{处理中};END{awk语句}'
awk 'BEGIN{FS=":";print "第一行\t\t第二行\n*************"};{print $NF"\t\t"$(NF-1)};END{print "*************"}' 1.txt
4、和正则的综合运用
运算符 | 说明 | |
---|---|---|
==,!=,>,<,>=,<= | 大于小于等于 | |
~ | 匹配 | |
!~ | 不匹配 | |
!,&&,|| | 逻辑非,与,或 |
awk -F: '/^root/,/^_lp/{print $0}' 1.txt # 以 root 开头 到 _lp开头 的行
awk -F: '/^root/;/^_lp/{print $0}' 1.txt # 以 root 开头 或者 _lp开头 的行
awk -F: '/^root/{print $0};/^_lp/{print $0}' 1.txt #和上面是等价的
awk 'NR>=1 && NR<=5 && $0 ~ /^root/{print $0}' 1.txt # 1到5行,并且以root开头的行
awk -F'[: ]' '{print $0}' 1.txt # 以冒号和空格为分割符
5、脚本编程
1、if结构
if [ xxx ];then
xxx
fi
awk 选项 '正则,地址定位{awk语句}' 文件名
awk 选项 '{if(表达式){语句1;语句2...}}'
awk 选项 '{if(表达式){语句1;语句2...} else {语句1;语句2...}}'
awk 选项 '{if(表达式){语句1;语句2...} else if(表达式){语句1;语句2...} else {语句1;语句2...}}'
awk -F: '{if($3=='4'){print $0}}' 1.txt # 第三个为4
awk -F: '{if($3>='60'){print $3" >60啊"} else {print $3"<60啊"}}' 1.txt
2、for循环
for ((int=1;i<=5;i++));do echo $i;done
awk 'BEGIN{for(i=1;i<=5;i++) {print i}}'
awk 'BEGIN{sum=0;for(i=1;i<=10;i+=2) sum=sum+i;{print sum}}'
3、while 循环
awk 'BEGIN{i=1;while(i<=5){print i;i++}}'
awk 'BEGIN{i=1;while(i<=5){print i;i++}}' | awk '{sum+=$0};END{print sum}'
awk 'BEGIN{sum=0;i=1;while(i<=10){print i;sum=sum+i;i++}{print sum}}'
4、嵌套循环
awk 'BEGIN{for(y=1;y<=5;y++){for(x=1;x<=y;x++){printf x};print "-----"}}'
5、运用实例
awk -F: '{shells[$NF]++};END{for (i in shells) print i,shells[i]}' 1.txt
小技巧
# & 后台输出,> 输出到/dev/null,这样在脚本输出结果中就不会展示信息了
ping -c1 $ip &>/dev/null
# 取出目录
dirname ~/Desktop
# 取出文件
basename ~/Desktop
###########################################
url=www.baidu.com
echo ${#url} # 获取url字符串的长度
echo ${url#*.} # 一个"#" 代表从左往右去掉一个/key/ ==> 结果是 baidu.com,去掉了 www.
echo ${url##*.} # 两个"#" 代表从左往右最大程度去掉/key/ ==> 结果是 com,去掉了 www.baidu.
echo ${url%.*} # 一个"%" 代表从右往左去掉一个/key/==> 结果是 www.baidu,去掉了右边的 .com
echo ${url%%.*} # 两个"#" 代表从右往左最大程度去掉/key/ ==> 结果是 www,去掉了 .baidu.com
################
# 在我们使用cat <<EOF时,我们输入完成后,需要在一个新的一行输入EOF结束stdin的输入。
cat <<EOF
h 显示帮助命令
f 显示磁盘分区
q 退出程序
EOF
# 分界符(EOF)所在行的开头部分的制表符(Tab)都将被去除。可以解决由于脚本中的自然缩进产生的制表符。
cat <<-EOF
h 显示帮助命令
f 显示磁盘分区
q 退出程序
EOF