shell特性([ ]判断、快捷键)

1、shell判断符[ ]

(()) () [] [[]] {}、字符截取(切片) - 凡人半睁眼 - 博客园 (cnblogs.com)

2、关系运算符只支持整数的比较,不支持字符串,除非字符串是变量并且值为整数!

[ ] 中使用的比较符[[ ]] 中使用的比较符(( )) 中使用的比较符作用
-eq 或 == -eq 或 == == 等于
-ne 或 != -ne 或 != != 不等于
-gt 或 \> -gt 或 > > 大于
-lt 或 \< -lt 或 < < 小于
-ge -ge >= 大于等于
-le -le <= 小于等于

还有:在 [ ] 中 使用 > 和 < 得用转义字符!而 [[ ]] 、(( )) 中不需要!

逻辑运算符:

[ ]中逻辑运算符[[ ]] 中逻辑运算符(( )) 中逻辑运算符作用
-a && & 或 && 两边的条件都成立,结果才为 true(与)
-o || | 或 || 一边条件成立则为 true(或)
条件为 true ,返回为 flase(非)

3、Shell脚本中的set指令,比如set -x 和 set -e,set  -u

set -x

打开脚本调试功能,也可以通过bash -x ***.sh打开

如果输出结果以双加号(++)开头则表示命令在子Shell中执行

set -n

检查shell语法,但不会执行,等同于bash -n xxx.sh

set -e

每个脚本都应该在文件开头加上set -e,这句语句告诉bash如果任何语句的执行结果不是true则应该退出。这样的好处是防止错误像滚雪球般变大导致一个致命的错

误,而这些错误本应该在之前就被处理掉。如果要增加可读性,可以使用set -o errexit,它的作用与set -e相同。

在"set -e"之后出现的代码,一旦出现了返回值非零,整个脚本就会立即退出。

set -o pipefail

设置了这个选项以后,包含管道命令的语句的返回值,会变成最后一个返回非零的管道命令的返回值

#!/bin/bash

set -o pipefail
ls a.txt | echo "hi" >/dev/null
[[ $? -ne 0 ]] && exit 1
echo "test"

结果

set -o pipefail是去捕获最后一个返回非零的管道命令的返回值,也就是ls a.txt的返回值;
没有a.txt文件,返回值为非0,因此[[ $? -ne 0 ]]条件成立,脚本退出,不执行echo “test”

set +h

hashall可以让Bash记录执行过的命令路径,并保存到一个内存的Hash表中,当再次执行相同命令时就不需要再通过PATH变量查找该命令的路径,这样可以提高效率。

但有时,程序的路径发生了变化,因为有Hash记录的存在反而会导致命令执行失败

set  -u

设置该选项后,当脚本在执行过程中尝试使用未定义过的变量时,报错并退出运行整个脚本(默认会把该变量的值当作空来处理)

set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。

-a  标示已修改的变量,以供输出至环境变量。
 -b  使被中止的后台程序立刻回报执行状态。
 -C  转向所产生的文件无法覆盖已存在的文件。
 -d  Shell预设会用杂凑表记忆使用过的指令,以加速指令的执行。使用-d参数可取消。
 -e  若指令传回值不等于0,则立即退出shell。  
 -f   取消使用通配符。
 -h  自动记录函数的所在位置。
 -H Shell  可利用"!"加<指令编号>的方式来执行history中记录的指令。
 -k  指令所给的参数都会被视为此指令的环境变量。
 -l  记录for循环的变量名称。
 -m  使用监视模式。
 -n  只读取指令,而不实际执行。
 -p  启动优先顺序模式。
 -P  启动-P参数后,执行指令时,会以实际的文件或目录来取代符号连接。
 -t  执行完随后的指令,即退出shell。
 -u  当执行时使用到未定义过的变量,则显示错误信息。
 -v  显示shell所读取的输入值。
 -x  执行指令后,会先显示该指令及所下的参数。
 +<参数>  取消某个set曾启动的参数

4、bash 内置命令exec

exec表示执行一个命令,但是不会启动子shell,而只是替代当前shell并且所有环境都会被清空。

注:source 和 . 不启用新的shell,在当前shell中执行,设定的局部变量在执行完命令后仍然有效;

bash或sh 或shell script执行时,另起一个子shell,其继承父shell的环境变量,其子shelll的变量执行完后不影响父shell,注意三类的区别

exec是用被执行的命令行替换掉当前的shell进程,且exec命令后的其他命令将不再执行。例如在当前shell中执行 exec ls 表示执行ls这条命令来替换当前的shell  即为执行完后会退出当前shell。

为了避免这个结果的影响,一般将exec命令放到一个shell脚本中,用主脚本调用这个脚本,调用处可以用bash  xx.sh(xx.sh为存放exec命令的脚本)。这样会为xx.sh

建立一个子shell去执行,当执行exec后该子脚本进程就被替换成相应的exec的命令

其中有一个例外:当exec命令对文件描述符操作的时候,就不会替换shell,而是操作完成后还会继续执行后面的命令

exec 3<&0 表示将操作符3也指向标准输入

exec ls          在shell中执行ls,ls结束后不返回原来的shell中了
 
exec <file       将file中的内容作为exec的标准输入
 
exec >file       将file中的内容作为标准写出
 
exec 3<file      将file读入到fd3中
 
sort <&3         fd3中读入的内容被分类
 
exec 4>file      将写入fd4中的内容写入file中
 
ls >&4           Ls将不会有显示,直接写入fd4中了,即上面的file中
 
exec 5<&4         创建fd4的拷贝fd5
 
exec 3<&-         关闭fd3

5、Linux中万物皆文件,文件描述符也是文件。默认:
    fd=0的标准输入是/dev/stdin文件
    fd=1的标准输出是/dev/stdout文件
    fd=2的标准错误是/dev/stderr文件

2>&1:将标准错误重定向到标准输出(常用)

特殊重定向:

&>file:这是特殊的重定向方式,表示将标准错误和标准输出都重定向到file文件中,等价于>file 2>&1
&>>file:这是特殊的重定向方式,表示将标准错误和标准输出都追加到file文件中,等价于>>file 2>&1

6、快速清空文本

: > access.log
> access.log
true > access.log
cat /dev/null > access.log
echo -n "" > access.log
echo > access.log
truncate -s 0 access.log

7、dd运用

dd快速生成大文件

$ dd if=/dev/zero of=file.txt  bs=1M count=1024

擦除硬盘数据

$ dd if=/dev/urandom of=/dev/sda

制作系统盘(sdb可以 U 盘,也可以是普通硬盘)

$ dd if=ubuntu-server-amd64.iso of=/dev/sdb

dd将小写字母全部转换成大写

$ dd if=testfile_2 of=testfile_1 conv=ucase

8、查看某个进程的运行时间(etime运行时间、rss内存)

ps -p 1858 -o etimes,etime
ELAPSED     ELAPSED
  22382    06:13:02

9、计算程序运行时间(time命令)

$ time ./test
real    0m1.003s
user    0m0.000s
sys     0m0.000s
  • real:表示的钟表时间,也就是从程序执行到结束花费的时间;
  • user:表示运行期间,cpu 在用户空间所消耗的时间;
  • sys:表示运行期间,cpu 在内核空间所消耗的时间;

由于 usersys 只统计 cpu 消耗的时间,程序运行期间会调用 sleep 发生阻塞,也可能会等待网络或磁盘 IO,都会消耗大量时间。因此对于类似情况,real 的值就会大于其它两项之和。另外,也会遇到 real 远远小于 user + sys 的场景,如果程序在多个 cpu 上并行,那么 usersys 统计时间是多个 cpu 时间,实际消耗时间 real 很可能就比其它两个之和要小了。

10、执行历史命令(实用)

  • !!:重复执行上条命令;
  • !N:重复执行 history 历史中第 N 条命令,N 可以通过 history 查看;
  • !pw:重复执行最近一次,以pw开头的历史命令,这个非常有用,小编使用非常高频;
  • !$:表示最近一次命令的最后一个参数;
$ vim /root/sniffer/src/main.c
$ mv !$ !$.bak
# 相当于
$ mv /root/sniffer/src/main.c /root/sniffer/src/main.c.bak11、Vim 保存一个没有权限的已编辑文件

在保存文件前更改文件权限。
命令是:
:w !sudo tee %
这个命令将会要你输入密码,就像在命令行中使用 sudo vim一样。

11、在命令 history 中显示时间戳
临时设置:

 export HISTTIMEFORMAT="%F %T `whoami` "

永久设置:

 echo 'export HISTTIMEFORMAT="%F %T `whoami` "' >> /etc/profile

12、间接引用变量

VAR1="2323232"
VAR2="VAR1"
变量VAR1和变量VAR2,这个VAR2的值是VAR1的名字,那么我们现在想通过VAR2来获取VAR1的值

$ echo ${!VAR2}
2323232

$ eval echo \$$VAR2
2323232

eval会对后面的cmdLine进行两遍扫描,如果在第一遍扫面后cmdLine是一个普通命令,则执行此命令;如果cmdLine中含有变量的间接引用

利用eval实现将结果分别赋值给变量

#cat tt.sh 
for i in $(echo "4 5 6"); do
   eval a$i=$i 
done
echo $a4 $a5 $a6

#cat tt1.sh 
num=0
for i in $(eval echo $*);do   #eval将{1,2}分解为1 2
   let num+=1
   eval node${num}="$i"
done
echo $node1 $node2 $node3
# bash a.sh 192.168.1.1{1,2}
192.168.1.11 192.168.1.12

13、shell脚本中“if”语法如何嵌套

if [ 条件 ]
then
命令1
命令2
…..
else
if [ 条件 ]
then
命令1
命令2
….
else
命令1
命令2
…..
fi
fi

14、数字运算

expr 1 + 2909
2910

test=$[16 + 4] 
$ echo $test
20

$let  5+2
7

###小数计算
echo "scale=2; 2.03+2.04" | bc

注:expr做数字的四则运算

  1. 请用空格隔开每个项。

  2. 请将反斜杠(\)放在 Shell 特殊字符前面。

  3. 请对包含空格和其他特殊字符的字符串用引号括起来。

15、shell高级变量

可以在替换字符串中任意满足条件的子串
${string/substring/replacement}    仅仅替换第一次匹配
${string//substring/replacement}     替换所有的匹配

范例:

zjz="123,124,zhz,zjksd"  #3设定字符串

str=${zjz//,/ }   ##替换字符串中的逗号为空格

echo $str     ##输出效果
123 124 zhz zjksd

脚本运用:字符串的替换

#cat tt.sh
#!/bin/bash
str="1,2,3,4";
str=${str//,/ };
arr=($str);

#遍历数组 for each in ${arr[*]} do echo $each done

16、shell特性之快捷键

ctrl + w   ##  从光标处删至该单词结束
ctrl + y   ## 撤销删除
ctrl +  k  ##  从光标处删除至行尾
ctrl +  u  ##  从光标处删除至行首

17、进制转换(2#表示:将1010二进制数转换为10进制数)

echo $(( 2#1010 ))

18、shell中${} 的用法,删除&替换

字符串的删除

echo  ${i##*/}   删除 / 前的所有内容

tt=$i
echo{tt:22} #取的22位以后的所有字符

实例

for i  in \
goharbor/harbor-core:v2.5.0 
goharbor/harbor-jobservice:v2.5.0 
goharbor/notary-signer-photon:v2.5.0 
goharbor/harbor-db:v2.5.0 
goharbor/harbor-registryctl:v2.5.0 
goharbor/redis-photon:v2.5.0 
goharbor/harbor-portal:v2.5.0 
goharbor/trivy-adapter-photon:v2.5.0 
goharbor/nginx-photon:v2.5.0 
goharbor/registry-photon:v2.5.0 
goharbor/notary-server-photon:v2.5.0 
goharbor/chartmuseum-photon:v2.5.0 
goharbor/prepare:v2.5.0 
goharbor/harbor-log:v2.5.0 
goharbor/harbor-exporter:v2.5.0 ;  \

do 
IMAGE=$(echo ${i##goharbor/} |cut -d: -f1); 
docker pull  mikrobithu/$IMAGE:dev-arm; 
docker tag mikrobithu/$IMAGE:dev-arm  goharbor/$IMAGE:v.2.5.0 ; 
docker tag mikrobithu/$IMAGE:dev-arm  goharbor/$IMAGE:v.dev-arm ; 
done

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
记忆的方法为:
# 是 去掉左边(键盘上#在 $ 的左边)
%是去掉右边(键盘上% 在$ 的右边)
单一符号是最小匹配;两个符号是最大匹配

取子串及替换
${file:0:5}:提取最左边的5 个字节:/dir1
${file:5:5}:提取第5 个字节右边的连续5个字节:/dir2
也可以对变量值里的字符串作替换:
${file/dir/path}:将第一个dir 替换为path:/path1/dir2/dir3/my.file.txt
${file//dir/path}:将全部dir 替换为path:/path1/path2/path3/my.file.txt
${#var} 可计算出变量值的长度:
${#file} 可得到27 ,因为/dir1/dir2/dir3/my.file.txt 是27个字节

echo ${PATH#*:} # 参数替换

${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
记忆的方法为:
[list]#是去掉左边, ##最后一个
      %是去掉右边, %%第一个
$  echo ${PATH}
/usr/local/share/miniconda3/bin/:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/op_admin/.local/bin:/home/op_admin/bin

echo ${PATH#*:}
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/op_admin/.local/bin:/home/op_admin/bin

$  echo ${PATH##*:}
/home/op_admin/bin

19、一行输入对个命令,使用 ; 隔开

 echo hello; echo there; echo zjz

20、逗号链接了一系列的算术操作,虽然里边所有的内容都被运行了,但只有最后一项被返回

let "t2 = ((a = 9, 15 / 3))"

#echo $t2
5
#echo $a
9

21、命令组()

在()中的命令列表,将作为一个子 shell 来运行,在()中的变量,由于是在子 shell 中,所以对于脚本剩下的部分是不可用的。

#(a=hello;echo $a)
hello

#echo $a
9

22、man帮助,常用1、5、8三个帮助级别

23、shell脚本中输出当前的路径的用法

方式1

path=$(cd `dirname $0`;pwd)

这条简单的命令就可以进入当前的路径,并且将路径值存在变量里。
- 首先是使用反引号包起来的dirname $0命令。使用反引号代表执行其中的命令并返回命令结果。$0代表脚本的文件名。这条指令就可以得到脚本的路径。
- 然后使用dirname通过文件名获取路径,因为$0并不是绝对路径,所以使用dirname得到的也不是绝对路径。这时使用cd进入,然后再使用pwd命令得到当前路径的绝对路径。

方式2

[ ! -d "$(realpath .)" ]
realpath . 会输出当前目录的绝对路径

24、shell的通配符和正则表达式

通配符:通配符是一种简单的模式匹配工具,通常用于文件名匹配。通配符可以用来匹配一个或多个字符

在 Bash shell 中,常用的通配符有以下几种:

星号(*):匹配任意数量的字符(包括零个或多个字符)。

问号(?):匹配单个任意字符。

方括号([ ]):匹配方括号内列举的任意一个字符。例如,[abc] 匹配 a、b 或 c 这三个字符中的任意一个。

连字符(-):用于表示范围,例如 [a-z] 表示匹配 a 到 z 之间的任意一个字符。

叹号加方括号([! ]):匹配任何不在方括号中列举的字符。

正则表达

则表达式是一种更强大的模式匹配工具,可以处理复杂的文本模式。它使用一些特殊的字符来表示文本模式,例如,点号(.)表示任何单个字符,星号(*)表示前面的字符可以出现零次或多次,加号(+)表示前面的字符可以出现一次或多次,等等。

正则表达式可以很方便地进行复杂的模式匹配,但是学习曲线比通配符要陡峭一些。

25、变量赋值给变量取值

worker_ip=${!worker_var}

while read -r line; do
    node_name=$(echo "$line" | awk -F',' '{print $1}')
    node_ip=$(echo "$line" | awk -F',' '{print $2}')
    eval "work_node$(printf %02d $ip_counter)=$node_ip"
    ((ip_counter++))
done < /tmp/list

if [ ${node_num} -ge 2 ]; then
    sed_command="sed -i.bak"
    # Replace the current node's IP
    sed_command+=" -e 's/ipaddr01/${curr_node_ip}/g'"
    # Replace the worker nodes' IPs
    for ((i=2; i<=node_num; i++)); do
        worker_var="work_node$(printf "%02d" $((i-1)))"
        worker_ip=${!worker_var}
        if [[ -n $worker_ip ]]; then
            sed_command+=" -e 's/ipaddr$(printf "%02d" $i)/${worker_ip}/g'"
        fi
    done
    # Apply the replacements
    sed_command+=" /etc/ansible/hosts"
    # Use sudo to execute sed command
    eval sudo $sed_command
else
    echo "Error: node_num must be 2 or greater."
    exit 1
fi

26、(( )) 支持变量的直接加减运算

node_num=2

 $((node_num + 1))

  

 

 

 

https://www.junmajinlong.com/shell/script_course/shell_tutorial/   骏马金龙
https://www.cnblogs.com/f-ck-need-u/p/7427357.html  shell测试命令test、[ ]、[[ ]]

posted @ 2019-09-25 20:56  凡人半睁眼  阅读(716)  评论(0编辑  收藏  举报