SECTION 30 常用命令进阶


本文为bash shell前面29章补充内容,无先后顺序,记录一些遇到的书中未提及的内容

30.1 COMMANDS

1. set

set -e 脚本前面设置该选项后,当脚本中任何以一个命令执行返回的状态码不为0时就退出整个脚本(默认脚本运行中某行报错会继续往下执行),这样就不必设置很多的判断条件去判断每个命令是否执行成功,特别那些依赖很强的地方,脚本任何一处执行报错就不应继续执行其他语句的时候就特别有用,之前写的一些像LAMP的安装脚本就深有体会。例如:

    #!/bin/bash
    set -e
    if [ "$1" = 'postgres' ]; then
        chown -R postgres "$PGDATA"
        if [ -z "$(ls -A "$PGDATA")" ]; then
            gosu postgres initdb
        fi
        exec gosu postgres "$@"
    fi
    exec "$@"

set -u 设置该选项后,当脚本在执行过程中尝试使用未定义过的变量时,报错并退出运行整个脚本(默认会把该变量的值当作空来处理),这个也非常有用,有些时候可能在脚本中变量很多很长,疏忽了把某个变量的名字写错了,这时候运行脚本不会报任何错误,但结果却不是你想要的,排查起来很是头疼,使用这个选项就完美的解决了这个问题。
set -x set +x命令的作用实际是用于输出详细日志,是Shell脚本中使用echo命令输出的替代方案。更适用于输出大量日志的场景使用
set -x 是开启,set +x是关闭,set -o是查看 (xtrace,追踪一段代码的显示情况)

[root@node-249 learn-terraform-docker-container]# set -x
+ set -x
++ printf '\033]0;%s@%s:%s\007' root node-249 /opt/learn-terraform-docker-container

2. cut

基本语法

cut [选项参数]  filename

说明:默认分隔符是制表符

选项与参数:

-d:分隔符,按照指定分隔符分割列。与 -f 一起使用
-f:依据 -d 的分隔字符将一段信息分割成为数段,用 -f 取出第几段的意思(列号,提取第几列)
-c:以字符 (characters) 的单位取出固定字符区间
-b:以字节为单位进行分割

示例:

  1. -d+-f 切割列
[root@node-251 yurq]# cut -d ':' -f 1 /etc/passwd		#切割第一列
root	
bin
daemon
...
[root@node-251 yurq]# cut -d ':' -f 2,4 /etc/passwd		#切割第二、四列
x:0
x:1
x:2
...
[root@node-251 yurq]# cut -d ':' -f 2-4 /etc/passwd		#切割第二到四列
x:0:0
x:1:1
x:2:2
x:3:4
  1. -c切割按字符位字符
[root@node-251 yurq]# cut -c 1-4 /etc/passwd
root
bin:
daem
  1. -b按字节位切割
[root@node-251 yurq]# cut -b 1,5,9 /etc/passwd
r::
bx1
do:

3. chattr

基本语法

chattr [+-=] [属性] 文件或目录名

+ 表示给文件或目录添加属性,
- 表示移除文件或目录拥有的某些属性
= 表示给文件或目录设定一些属性

chattr 命令常用的属性选项及功能

属 性说明
i如果对文件设置 i 属性,那么不允许对文件进行删除、改名,也不能添加和修改数据; 如果对目录设置 i 属性,那么只能修改目录下文件中的数据,但不允许建立和删除文件;
a如果对文件设置 a 属性,那么只能在文件中増加数据,但是不能删除和修改数据;如果对目录设置 a 属性,那么只允许在目录中建立和修改文件,但是不允许删除文件;
u设置此属性的文件或目录,在删除时,其内容会被保存,以保证后期能够恢复,常用来防止意外删除文件或目录。
s和 u 相反,删除文件或目录时,会被彻底删除(直接从硬盘上删除,然后用 0 填充所占用的区域),不可恢复。

i属性可用于系统文件保护,a属性可用于内容备份

示例:
i属性演示

[root@node-251 yurq]# mkdir test_dir;touch test_file	#建立文件及目录
[root@node-251 yurq]# ll
total 4
-rw-r--r-- 1 root root  0 May 31 23:33
-rwxr--r-- 1 root root 90 Jun  1 16:46 lock.sh
drwxr-xr-x 2 root root 24 Apr 24 22:56 sql_data_bak
drwxr-xr-x 2 root root  6 Jun  1 21:27 test_dir
-rw-r--r-- 1 root root  0 Jun  1 21:27 test_file
[root@node-251 yurq]# chattr +i test_file				#添加属性
[root@node-251 yurq]# ll
total 4
-rw-r--r-- 1 root root  0 May 31 23:33
-rwxr--r-- 1 root root 90 Jun  1 16:46 lock.sh
drwxr-xr-x 2 root root 24 Apr 24 22:56 sql_data_bak
drwxr-xr-x 2 root root  6 Jun  1 21:27 test_dir
-rw-r--r-- 1 root root  0 Jun  1 21:27 test_file
[root@node-251 yurq]# rm -rf test_file					#无法删除文件
rm: cannot remove ‘test_file’: Operation not permitted	
[root@node-251 yurq]# mv test_file test_file_1			#无法重命名文件
mv: cannot move ‘test_file’ to ‘test_file_1’: Operation not permitted
[root@node-251 yurq]# echo 123 > test_file				#无法修改内容
-bash: test_file: Permission denied
[root@node-251 yurq]# chattr +i test_dir/				#添加目录属性
[root@node-251 yurq]# rm -rf test_dir					#无法删除目录
rm: cannot remove ‘test_dir’: Operation not permitted
[root@node-251 yurq]# echo 123> test_dir/test			#无法修改目录内文件内容
-bash: test_dir/test: Permission denied
[root@node-251 yurq]# chattr -i test_dir/				
[root@node-251 yurq]# echo 123> test_dir/test

[root@node-251 yurq]# chattr +i test_dir/
[root@node-251 yurq]# echo 321 >> test_dir/test
[root@node-251 yurq]# rm -rf test_dir/test				#无法删除文件
rm: cannot remove ‘test_dir/test’: Permission denied

a属性显示

[root@localhost ~]# mkdir -p /back/log
#建立备份目录
[root@localhost ~]# chattr +a /back/log
#赋予a属性
[root@localhost ~]# cp /var/log/messages /back/log
#可以复制文件和新建文件到指定目录中
[root@localhost ~]# rm -rf /back/log/messages
rm: cannot remove '/back/log/messages': Permission denied
#无法删除 /back/log/messages,操作不允许

4. getfacl/setfacl(ACL)

当一个文件要对多个用户设置不同的使用权限是,简单的权限管理(一个用户,一个组,一个其他人)已经无法满足需求.
这个时候,我们就需要使用ACL权限 (Access Control list访问控制列表),对文件的ACL设置可以通过ACL让特定的用户或组对其设置特别的权限

ACL和UGO的区别

UGO基本权限:只能一个用户、一个组合、其他人这三个对象进行授权
ACL文件权限管理:设置不同用户,不同的基本权限(r、w、x),对象数量不同

所谓的 ugo 就是指 user(也称为 owner)、group 和 other 三个单词的首字母组合

setfacl命令(set设置,f文件file,acl访问控制列表)添加文件的ACL

基本语法

setfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file ...

参数:

-m:设定 ACL 权限。如果是给予用户 ACL 权限,则使用"u:用户名:权限"格式赋予;如果是给予组 ACL 权限,则使用"g:组名:权限" 格式赋予;
-x:删除指定的 ACL 权限;
-b:删除所有的 ACL 权限;
-d:设定默认 ACL 权限。只对目录生效,指目录中新建立的文件拥有此默认权限;
-k:删除默认 ACL 权限;
-R:递归设定 ACL 权限。指设定的 ACL 权限会对目录下的所有子文件生效;
1. 给用户添加ACL
[root@localhost ~]# useradd zhangsan
[root@localhost ~]# useradd lisi
[root@localhost ~]# useradd st
[root@localhost ~]# groupadd tgroup
#添加需要试验的用户和用户组,省略设定密码的过程
[root@localhost ~]# mkdir /project #建立需要分配权限的目录
[root@localhost ~]# chown root:tgroup /project/
#改变/project目录的属主和属组
[root@localhost ~]# chmod 770 /project/
#指定/project目录的权限
[root@localhost ~]# ll -d /project/
drwxrwx--- 2 root tgroup 4096 1月19 04:21 /project/
#查看一下权限,已经符合要求了
#这时st学员来试听了,如何给她分配权限
[root@localhost ~]# setfacl -m u:st:rx /project/
#给用户st赋予r-x权限,使用"u:用户名:权限" 格式
[root@localhost /]# cd /
[root@localhost /]# ll -d project/
drwxrwx---+ 3 root tgroup 4096 1月19 05:20 project/
#使用ls-l査询时会发现,在权限位后面多了一个"+",表示此目录拥有ACL权限
[root@localhost /]# getfacl project
#查看/prpject目录的ACL权限
#file: project <-文件名
#owner: root <-文件的属主
#group: tgroup <-文件的属组
user::rwx <-用户名栏是空的,说明是属主的权限
user:st:r-x <-用户st的权限
group::rwx <-组名栏是空的,说明是属组的权限
mask::rwx <-mask权限
other::--- <-其他人的权限
2. 给用户组赋予 ACL 权限
[root@localhost /]# groupadd tgroup2
#添加测试组
[root@localhost /]# setfacl -m g:tgroup2:rwx project/
#为组tgroup2纷配ACL权限,使用"g:组名:权限"格式
[root@localhost /]# ll -d project/
drwxrwx---+ 2 root tgroup 4096 1月19 04:21 project/
#属组并没有更改
[root@localhost /]# getfacl project/
#file: project/
#owner: root
#group: tgroup
user::rwx
user:st:r-x
group::rwx
group:tgroup2:rwx <-用户组tgroup2拥有了rwx权限
mask::rwx
other::--
3. 最大有效权限mask

mask 是用来指定最大有效权限的。mask 的默认权限是 rwx,如果我给 st 用户赋予了 r-x 的 ACL 权限,mj 需要和 mask 的 rwx 权限"相与"才能得到 st 的真正权限,也就是 r-x "相与"rwx出的值是 r-x,所以 st 用户拥有 r-x 权限。

如果把 mask 的权限改为 r–,和 st 用户的权限相与,也就是 r–"相与"r-x 得出的值是 r–,st 用户的权限就会变为只读。大家可以这么理解:用户和用户组所设定的权限必须在 mask 权限设定的范围之内才能生效,mask权限就是最大有效权限。

不过我们一般不更改 mask 权限,只要给予 mask 最大权限 rwx,那么任何权限和 mask 权限相与,得出的值都是权限本身。也就是说,我们通过给用户和用户组直接赋予权限,就可以生效,这样做更直观。

[root@localhost /]# setfacl -m m:rx project/
#设定mask权限为r-x,使用"m:权限"格式
[root@localhost /]# getfacl project/
#file:project/
#owner:root
#group:tgroup
user::rwx
group::rwx #effective:r-x
mask::r-x
#mask权限变为r-x
other::--
4. 递归 ACL 权限

默认 ACL 权限的作用是:如果给父目录设定了默认 ACL 权限,那么父目录中所有新建的子文件都会继承父目录的 ACL 权限

[root@localhost project]# setfacl -m u:st:rx -R /project/
#-R递归
[root@localhost project]# ll
总用量8
-rw-r-xr--+ 1 root root 01月19 05:20 abc
-rw-rwx--+ 1 root root 01月19 05:33 bcd
drwxr-xr-x+ 2 root root 4096 1月19 05:20 d1
drwxrwx--+ 2 root root 4096 1月19 05:33 d2
#abc和d1也拥有了ACL权限
5. 删除ACL权限

删除指定的ACL权限:

[root@localhost /]# setfacl -x u:st /project/
#删除指定用户和用户组的ACL权限
[root@localhost /]# getfacl project/
# file:project/
# owner: root
# group: tgroup
user::rwx
group::rwx
group:tgroup2:rwx
mask::rwx
other::--
#st用户的权限已被删除

删除所有ACL权限:

[root@localhost /]# setfacl -b project/
#会删除文件的所有ACL权限
[root@localhost /]# getfacl project/
#file: project/
#owner: root
# group: tgroup
user::rwx
group::rwx
other::--
#所有ACL权限已被删除

5. dd

dd 命令用于读取、转换并输出数据。可从标准输入或文件中读取数据,根据指定的格式来转换数据,再输出到文件、设备或标准输出。

语法格式:

dd [operand]
dd option

常用参数:

  • bs=BYTES:同时设置输入/输出的块大小为BYTES字节

  • count=N:仅拷贝N个block块,块大小等于ibs指定的字节数

  • cbs=BYTES:一次转换BYTES个字节,即指定转换缓冲区大小

  • ibs=BYTES:一次读取BYTES个字节,即指定读取的一个块大小为BYTES字节

  • obs=BYTES:一次输出BYTES个字节,即指定输出的一个块大小为BYTES字节

  • if=FILE:输入文件名,默认为标准输入

  • iflag=FLAGS

  • of=FILE:输出文件名,默认为标准输出

  • oflag=FLAGS

  • skip=N:从输入文件开头跳过N个block块后开始复制

  • seek=N:从输出文件开头跳过N个block块后开始复制

  • status=LEVEL:打印到stderr的信息级别

      node: 抑制错误消息之外的所有内容
      noxfer: 抑制最终的传输统计数据
      progress:显示定期传输统计信息
    
  • conv=<CONVS KEY WORDS>,设置关键字信息来转换文件。默认值conv=sync,参数conv的关键字有以下几种:

      conversion:用指定的参数转换文件。
      ascii:转换ebcdic为ascii
      ebcdic:转换ascii为ebcdic
      ibm:转换ascii为alternate ebcdic
      block:把每一行转换为长度为cbs,不足部分用空格填充
      unblock:使每一行的长度都为cbs,不足部分用空格填充
      lcase:把大写字符转换为小写字符
      ucase:把小写字符转换为大写字符
      swap:交换输入的每对字节
      noerror:出错时不停止
      notrunc:不截短输出文件
      sync:将每个输入块填充到ibs个字节,不足部分用空(NUL)字符补齐。
    

生成一个200M的新文件。/dev/zero的文件可以产生无穷的数据,使用这个设备配合dd使用,就能创建一个指定大小的文件。

[root@localhost ~]# dd if=/dev/zero of=1.txt bs=10M count=20
记录了20+0 的读入
记录了20+0 的写出
209715200字节(210 MB)已复制,3.69047 秒,56.8 MB/秒
[root@localhost ~]# ll -h 1.txt
-rw-r--r--. 1 root root 200M 226 11:16 1.txt

6. /dev/zero

该文件是一个特殊的字符设备文件,当我们使用或者读取它的时候,它会提供无限连续不断的空数据流(特殊的数据格式流),其中一个典型的用法就是用它提供的字符流来覆盖信息,另一个常见用法就是产生一个特定大小的空白文件。

示例:
生成块大小1M,含有2个块的文件,在使用dd 命令产生空文件时常用/dev/zero作为字符流的源

dd if=/dev/zero of=1.txt bs=1M count=2

利用/dev/zero文件覆盖其他文件信息,创建一个新文件写入12345字符串,用空的字符流覆盖存在的2.txt文件

echo 12345>2.txt
cat 2.txt
12345
dd if=/dev/zero of=2.txt bs=1M count=6
cat 2.txt

7. getopts

getopts命令是用来解析Shell脚本命令行参数的工具,getopts命令参数包含需要被识别的选项字符,如果选项字符后面跟着一个冒号,则表明该字符选项需要一个命令行参数(选项字符与对应的命令行参数之间以空格分隔)(注意:冒号&问号不能被用作为选项字符)。getopts命令每次被调用时,它会将下一个选项字符放置到变量中,OPTARG则可以拿到参数值;如果option前面加冒号,则代表忽略错误

命令使用格式

getopts optstring name [arg...]
  • optstring列出了对应的Shell脚本可以识别的所有参数,例如:需要使用-a,-f,-s参数时,optstring是afs;如果需要命令行参数后面还跟随一个值,则在相应的optstring后面加冒号,例如a:fs 表示a命令行参数后面会有一个值,是**-a value**的形式;
  • getopts执行时若匹配到a参数,会把-a参数对应的value存放在一个叫OPTARG的Shell Variable中;
  • 如果optstring是以冒号开头,则表明当命令行出现了optstring中没有的参数将不会提示错误信息
#!/bin/bash

func() {
    echo "Usage:"
    echo "test.sh [-j S_DIR] [-m D_DIR]"
    echo "Description:"
    echo "S_DIR,the path of source."
    echo "D_DIR,the path of destination."
    exit -1
}

upload="false"

while getopts 'h:j:m:u' OPT; do
    case $OPT in
        j) S_DIR="$OPTARG";;
        m) D_DIR="$OPTARG";;
        u) upload="true";;
        h) func;;
        ?) func;;
    esac
done

echo $S_DIR
echo $D_DIR
echo $upload
sh test.sh -j /data/usw/web -m /opt/data/web
##输出结果
/data/usw/web
/opt/data/web
false

getopts命令的选项字符中,如果是没有跟随 : 的字母就是开关型选项,不需要指定值,等同于true/false,只要带上了这个参数就是true。如下示例中的 -u

getopts命令识别出各个选项之后,就可以配合case进行操作。操作中,有两个"常量",一个是OPTARG,用来获取当前选项的值;另外一个就是OPTIND,表示当前选项在参数列表中的位移。case的最后一项是?,是用来识别非法的选项,并进行相应的操作,我们的脚本中是输出了帮助信息

sh test.sh -j /data/usw/web -m /opt/data/web -u
##输出结果
/data/usw/web
/opt/data/web
true

8. 彩色echo

echo -e  "\033[31m123\033[0m"	#red

echo -e  "\033[32m123\033[0m"	#green

echo -e  "\033[33m123\033[0m"	#yellow

echo -e  "\033[34m123\033[0m"	#blue

9. bc -l

[root@server shells]# threshold=1
[root@server shells]# mem_info=$(free | awk 'NR==2{print $3/$2 * 100}')
[root@server shells]# echo "$mem_info > $threshold"
51.3596 > 1
[root@server shells]# echo "$mem_info > $threshold"|bc -l
1

把字符串提供给bc进行计算

10. /bin/sh -c

比如要向 123 文件中随便写入点内容,可以:

[yurq@node-137 ~]$ echo 123 > /root/123
-bash: /root/123: Permission denied

然后,我们使用 sudo 并配合 echo 命令再次向修改权限之后的 123 文件中写入信息:

[yurq@node-137 ~]$ sudo echo 123 > /root/123
-bash: /root/123: Permission denied

这时可以看到 bash 拒绝这么做,说是权限不够。这是因为重定向符号 “>” 和 “>>” 也是 bash 的命令。我们使用 sudo 只是让 echo 命令具有了 root 权限,但是没有让 “>” 和 “>>” 命令也具有 root 权限,所以 bash 会认为这两个命令都没有像 123 文件写入信息的权限。
解决这一问题的途径有两种。

  • 第一种是利用 “sh -c” 命令,它可以让 bash 将一个字串作为完整的命令来执行,这样就可以将 sudo 的影响范围扩展到整条命令。具体用法如下:
[yurq@node-137 ~]$ sudo /bin/sh -c 'echo "123" > /root/123'
  • 另一种方法是利用管道和 tee 命令,该命令可以从标准输入中读入信息并将其写入标准输出或文件中,具体用法如下:
[yurq@node-137 ~]$ echo "234"|sudo tee -a 234

注意,tee 命令的 “-a” 选项的作用等同于 “>>” 命令,如果去除该选项,那么 tee 命令的作用就等同于 “>” 命令

以上两种方法的前提是/etc/sudoers中对该用户添加了对应命令的权限

11. let

简单的计算器,执行算术表达式。格式,

let arg [arg ...]

参数

arg:算术表达式

返回值

当let最后一个执行的表达式的计算结果为0时返回1,否则返回0。 当let执行的表达式的除数为0时,返回1并报错。

运算符优先级递减表
运算符描述
id++, id–变量后增量、变量后减量
++id, --id变量预增量、变量预减量
-, +正号、负号
!, ~逻辑否、按位取反
**幂运算
*, /, %乘法、除法、取余
+, -加法、减法
>>,<<按位左移、右移
=,比较
==, !=等于、不等于
&按位与
^按位异或
|按位或
&&逻辑与
||逻辑或
expr ? expr : expr条件运算符(三元运算符)
=, *=, /=, %=, +=, -=, >=, &=, ^=, |=赋值

自增自减

i=1
let i++
let i--

let i=i+20
关于let、expr、[ ]

原生bash不支持简单的数学运算,需通过expr

[root@server ~]# a=1 b=2
[root@server ~]# echo $a $b
1 2
[root@server ~]# echo `expr $a+$b`
1+2
[root@server ~]# echo `expr $a + $b`
3
[root@server ~]# echo `expr $a * $b`
expr: syntax error: unexpected argument ‘123’

[root@server ~]# echo `expr $a \* $b`
2

表达式和运算符之间要有空格,且这里是偏引号

[root@server ~]# echo $[a+b] $a+$b
3 1+2

关于这三个的区别和联系,看达到同样效果,它们各自如何实现:

    a=$[1+1]
    a=$((1+1))
    let a=1+1
    a=$(expr 1 + 1 )

12. cpio

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值