shell脚本的一些补充(进阶)

16 篇文章 0 订阅
4 篇文章 0 订阅

运算符

+加法expr $a + $b 结果为 30。
-减法expr $a - $b 结果为 -10。
*乘法expr $a \* $b 结果为 200。
/除法expr $b / $a 结果为 2。
%取余expr $b % $a 结果为 0。
=赋值a=$b 将把变量 b 的值赋给 a。
==相等。用于比较两个数字,相同则返回 true。[ $a == $b ] 返回 false。
!=不相等。用于比较两个数字,不相同则返回 true。[ $a != $b ] 返回 true。

三元运算

expr1?expr2:expr3

比较(三元组)操作.如果表达式expr1非零(算术为true),那么执行expr2,否则执行expr3

shell内置变量含义

1. $$
Shell本身的PID(ProcessID)

2. $!
Shell最后运行的后台Process的PID


3. $?
最后运行的命令的结束代码(返回值)


4. $-
使用Set命令设定的Flag一览


5. $*
所有参数列表。如"$*"用「"」括起来的情况、以"$1 $2 … $n"的形式输出所有参数。


6. $@
所有参数列表。如"$@"用「"」括起来的情况、以"$1" "$2" … "$n" 的形式输出所有参数。

7. $#
添加到Shell的参数个数


8. $0
Shell本身的文件名


9.$1~$n
添加到Shell的各参数值。$1是第1参数、$2是第2参数…。

!$ 和$_ 的区别

  • !$会打印上一行命令的最后一个参数,$_则会打印上一个命令的最后一个参数(无论是否在同一行内)
  1. !$示例:
     echo 111
     echo 222 && echo !$              # 输出上一行命令最后参数  111
     
     echo 111
     echo 222 ; echo !$				# 输出上一行命令最后参数  111
  1. !_示例:
     echo 111
     echo 222 && echo !_             # 输出上一个命令最后参数  222
     
     echo 111
     echo 222 ; echo !_				# 输出上一个命令最后参数  222

赋值操作符

以下示例,在变量不为空时,a=1

格式列子未定义变量为空变量不为空补充
=echo ${a=2}2null1
:=echo ${a:=2}221
:-echo ${a:-2}221不会赋值给变量,只有在运行阶段替换${}
-echo ${a-2}2nullnull不会赋值给变量,只有在运行阶段替换${}
:?echo ${a:?2}221不会赋值给变量,只有在运行阶段替换${},
变量已被定义但却没有一个真正的值(也就是说非空)或者完全未被定义并且脚本退出执行
?echo ${a?2}2null1如果username变量没有被定义,执行LOGNAME替换,
脚本退出运行,并显示退出时所在代码行在脚本中的位置。
:+echo ${a:+2}nullnull2
+echo : ${a+2}null22

${var} 和 ${!var}

! v a r 是 指 取 变 量 时 变 量 名 从 v a r 中 动 态 得 到 , 而 不 是 直 接 的 字 面 量 v a r 。 v a r 可 以 是 其 它 合 法 的 变 量 名 , 如 {!var}是指取变量时变量名从var中动态得到,而不是直接的字面量var。var可以是其它合法的变量名,如 !varvarvarvar{!aaa}、${!bbb}

  • ! v a r 可 以 理 解 为 递 归 取 值 , 获 得 变 量 v a r 的 值 后 , 继 续 取 名 为 {!var} 可以理解为递归取值,获得变量var的值后,继续取名为 !var,var,var的变量的值

f1() {
local var="$1"
echo "${!var}"
}
 
f1 1  --结果 1,相当于echo "${1}"
f1 2 b --结果 b, 相当于echo "${2}"
  • ${var} 取变量var的值

f1() {
local var="$1"
echo "${var}"
}
 
f1 1  --结果 1
f1 2 b --结果 2

返回变量名

  • ${!var*}${!var@}返回以指定字符串开头的变量名,两个方式效果一样

bash 中的 ${ # % / } 字符串操作符

使用#和%删除字符串

变量: file=/dir1/dir2/dir3/my.file.txt

${     # */  }   ${   ##  }   ${   % }      ${     %%  }

${file#*/}:删掉第一个 / 及其左边的字符串:dir1/dir2/dir3/my.file.txt
${file##*/}:删掉最后一个 / 及其左边的字符串:my.file.txt
${file#*.}:删掉第一个 . 及其左边的字符串:file.txt
${file##*.}:删掉最后一个 . 及其左边的字符串:txt
${file%/*}:删掉最后一个 / 及其右边的字符串:/dir1/dir2/dir3
${file%%/*}:删掉第一个 / 及其右边的字符串:(空值)
${file%.*}:删掉最后一个 . 及其右边的字符串:/dir1/dir2/dir3/my.file
${file%%.*}:删掉第一个 . 及其右边的字符串:/dir1/dir2/dir3/my
记忆的方法为:

# 是去掉左边(键盘上#在 $ 的左边)
% 是去掉右边(键盘上% 在$ 的右边)
单一符号是最小匹配;两个符号是最大匹配
使用//替换字符串
${var/     /     }    ${var//       /    }

//  对变量值里的字符串作替换:

${file/dir/path}:将第一个dir 替换为path:/path1/dir2/dir3/my.file.txt
${file//dir/path}:将全部dir 替换为 path:/path1/path2/path3/my.file.txt

示例:

$ strip_all "The Quick Brown Fox" "[aeiou]"         #剔除aeiou
Th Qck Brwn Fx

$ strip_all "The Quick Brown Fox" "[[:space:]]"     #剔除空格
TheQuickBrownFox

$ strip_all "The Quick Brown Fox" "Quick "			#剔除Quick
The Brown Fox

字符串大小写转换

转换成小写

使用${,}替换字符串中的大写字母为小写

string='ABcde'
echo ${string,,}    # 输出  abcde
转换成大写

使用${^^}替换字符串中的小写字母为大写

string='ABcde'
echo ${string^^}    # 输出  ABCDE
反转字符串大小写

使用${~~}反转字符串中的字母大小写

string='AbCdE'
echo ${string~~}    # 输出 aBcDe

进程替换<()

进程替换是把一个进程的输出回馈给另一个进程

  • 格式

    由圆括号括起的命令

    >(command)
    >>(command)
    <(command)
    <<(command)
    
  1. 在"<" 或or “>” 与圆括号之间是没有空格的. 如果加了空格将会引起错误信息.
  cat <(ls -l)	# 等同于     ls -l | cat
  
  sort -k 9 <(ls -l /bin) <(ls -l /usr/bin) 
  # 列出系统中2个主要的'bin'目录的所有文件,并且按文件名排序.
  # 注意是三个明显不同的命令输出回馈给'sort'.

here-string <<<的使用

  • 格式
<<< strings

字符串将被扩展并通过标准输入提供给命令

在bash中,引入管道意味着单个命令将在子shell中运行

echo "hello world" | read first second
echo $second $first 				# 输出为空行

第二个echo命令的输出仅打印一个空格。因为read命令在管道中,所以它在子shell中运行。它从stdin读取2个单词并分配给变量。但是随后命令完成,子shell退出并且变量丢失。

有时,也可以使用花括号解决此问题:

echo "hello world" | {
    read first second
    echo $second $first
}

但是在脚本的当前shell中仍然没有这些变量。要解决这种情况,就需要使用here-string

read first second <<< "hello world"
echo $second $first

<<的使用

<< 表示此处的文档。

$ cat <<EOF
> hi
> there
> EOF

输出:
hi
there

其中EOF: 可以是任何单词。可以理解为定界符

< 将文件的内容传递到命令的标准输入(输入重定向)

cat < /etc/fstab
/dev/sda2               /boot   ext4            nosuid,noexec,nodev,rw,noatime,nodiratime       0 2
/dev/sda4               /       ext4            rw,noatime,nodiratime,  0 1
/dev/sdb5               /var    ext4            nosuid,noexec,nodev,rw,relatime 0 2
 ...

文件描述符(fd)

文件描述符通道名描述默认连接用途
0stdin标准输入键盘read only
1stdout标准输出终端write only
2stderr标准错误终端write only
3以上filename其他文件noneread and/or write
  • 操作
命令作用例子说明
&1指定文件描述符,可以是任意描述符(此处为1)echo “test” >1.txt 2>&1将错误输出重定向到标准输出
&包含所有文件描述符echo “test” &>1.txt将标准和错误都重定向
&-关闭文件描述符exec 3>&-关闭文件描述符fd3
  • exec操作文件描述符
exec 3>access.log					# 定义fd3 输出到 access.log
echo "这是文件描述符fd3" >&3           # 将标准输出重定向到 fd3
exec 3<&-;exec 3>&- 					    # 关闭文件描述符 fd3
  1. 一旦关闭了文件描述符,就不能在脚本中向它写入任何数据,否则shell会生成错误消息
  2. echo “hello” >&3 向文件描述符中输入内容只使用 > 不能用 >> ,此时的 > 不会清空文件
  3. 是否清空文件需要在exec命令关联文件描述符到文件的时候区别使用 > 或 >>
  4. read -u 命令可以读取指定文件描述符

进程

fork
  1. fork是linux的系统调用,用来创建子进程(child process)。子进程是父进程(parent process)的一个副本,从父进程那里获得一定的资源分配以及继承父进程的环境。
  2. 子进程与父进程唯一不同的地方在于pid(process id)。
  3. 环境变量(传给子进程的变量,遗传性是本地变量和环境变量的根本区别)只能单向从父进程传给子进程。不管子进程的环境变量如何变化,都不会影响父进程的环境变量。
  4. export会把父进程中的变量向子进程中继承,但是反过来却不行
source(.) 和sh 和exec的区别
sh:父进程会fork一个子进程,shell script在子进程中执行

source:在原进程中执行,不会fork子进程

exec:在原进程中执行,但是同时会终止原进程
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值