【一、 Linux提高命令行运行效率】

1. 编写简单的 Bash 脚本

1.1 创建和执行 shell 脚本

  • 脚本的第一行以符号 # ! 开头,此符号是一个解释器指令,指示处理文件的其余行所需的命令解释器和、命令选项。对于 Bash 语法脚本文件,第一行就是以下指令:#!/bin/bash
  • shell 脚本必须为可执行文件,使用 chmod 命令可添加执行权限。
  • 可将脚本放在 shell 的 PATH 环境变量列出的目录中,即可直接输入脚本名来运行,示例:
    [user@host ~]$ which hello
    /bin/hello
    [user@host ~]$ echo $PATH
    /home/user/.local/bin:/home/user/bin:/usr/share/Modules/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin
    
  • 或使用 ./ 在当前工作目录中运行脚本,例如 ./scriptname

1.2 对特殊字符加引号

  • 一些字符和词语对 Bash shell 具有特殊含义,有时希望使用这些字符的字面值,而非其特殊含义。 以下三种工具之一可以取消(或转义)特殊含义:反斜杠(\);单引号(‘ ’);双引号(" "),示例:一-第三章-5-防止参数被扩展
    [user@host ~]$ echo #not a comment#
    [user@host ~]$ echo \#not a comment#
    #not a comment#
    [user@host ~]$ echo \#not a comment\#
    #not a comment#
    [user@host ~]$ echo '#not a comment#'
    #not a comment#
    

1.3 从 Shell 脚本提供输出

  • 通过将文本作为参数传递给命令,echo 命令可显示任意文本,默认情况下,文本将在标准输出(STDOUT)上显示,示例:
    [user@host ~]$ cat /bin/hello
    #!/bin/bash
    echo "Hello,world"
    [user@host ~]$ hello(命令)
    Hello,world
    

/bin/hello 是一个可执行脚本:创建的 hello 脚本位于 /bin/hello,并且已经具有可执行权限(假设已经进行了 chmod +x /bin/hello),所以可以直接在命令行输入 hello 来执行它。
$PATH 是一个环境变量,其中列出了操作系统查找可执行命令时需要遍历的目录。当在命令行输入命令时,系统会在 $PATH 中列出的所有目录中查找对应的可执行文件。如果找到了就执行它。

hello 命令可以直接运行,是因为它位于系统的 /bin 目录下,而 /bin 目录已经包含在 $PATH 环境变量中。

如果将脚本放在其他目录下(比如当前目录),需要使用 ./hello 来执行它,因为当前目录(./)通常不在 $PATH 中。

/bin 是 $PATH 中的一个目录,所以当输入 hello 时,系统会在 /bin 目录下找到 hello 脚本并执行它。

  • 也可以使用输出重定向将其定向到标准错误(STDERR),示例:
    [user@host ~]$ cat /bin/hello
    #!/bin/bash
    echo "Hello,world"
    echo "ERROR:Houston,we have a problem.">&2
    [user@host ~]$ hello 2> hello.log
    Hello,world
    [user@host ~]$ cat hello.log
    ERROR:Houston,we have a problem.
    

>&2: 这部分是将 标准输出(stdout) 重定向到 标准错误(stderr),即 echo 输出的内容会发送到错误流(stderr)而不是常规的输出流(stdout)。但它并不意味着命令本身出错。它只是告诉系统:“虽然这不是错误信息,但我希望它走错误流。”

2. 脚本中的循环和条件结构

2.1 使用循环来迭代命令

  • Bash 的 for 循环结构使用以下语法:for VARIABLE in LIST; do COMMAND $VARIABLE; done,示例:
    [user@host ~]$ for HOST in host1 host2 host3; do echo $HOST; done
    host1
    host2
    host3
    [user@host ~]$ for HOST in host{1,2,3}; do echo $HOST; done
    host1
    host2
    host3
    [user@host ~]$ for HOST in host{1..3}; do echo $HOST; done
    host1
    host2
    host3
    [user@host ~]$ for FILE in file*; do ls $FILE; done
    filea
    fileb
    filec
    [user@host ~]$ for FILE in file{a..c}; do ls $FILE; done
    filea
    fileb
    filec
    [user@host ~]$ for PACKAGE in $(rpm -qa | grep kernel); do echo "$PACKAGE was installed on $(date -d @$(rpm -q --qf %{INSTALLTIME}n $PACKAGE))"; done
    abrt-addon-kernelops-2.1.11-12.el7.x86_64 was installed on Tue Apr 22 00:09:07 EDT 2014
    kernel-3.10.0-121.el7.x86_64 was installed on Thu Apr 10 15:27:52 EDT 2014
    kernel-tools-3.10.0-121.el7.x86_64 was installed on Thu Apr 10 15:28:01 EDT 2014
    kernel-tools-libs-3.10.0-121.el7.x86_64 was installed on Thu Apr 10 15:26:22 EDT 2014
    [user@host ~]$ for EVEN in $(seq 2 2 10); do echo "$EVEN"; done
    2
    4
    6
    8
    10
    

2.2 在脚本使用退出代码

  • 在处理完所有内容后,脚本会退出到调用它的进程,但是,有时候可能需要在完成之前退出脚本,比如在遇到错误条件时,可在脚本中使用 exit 命令来实现这一目的。
  • 可使用整数参数(0 到 255 之间,表示退出代码)来执行 exit 命令,退出代码是进程完成后返回的代码,0 表示没有错误;非零值都表示存在错误。
  • 可以使用不同的非零值来区分遇到的不同类型错误,此退出代码传回到父进程,并存储在 ? 变量中,可通过 $? 访问退出代码,示例:
    [user@host bin]$ cat hello
    #!/bin/bash
    echo "Hello,world"
    exit 0
    [user@host bin]$ ./hello
    Hello,world
    [user@host bin]$ echo $?
    0
    

2.3 测试脚本输入

[ … ] 是条件测试命令(其实是 test 命令的简写)。

它的执行结果(真 / 假)通过特殊变量 $? 表示:

$? = 0 → 表示条件为 真 (True);

$? = 1 → 表示条件为 假 (False)。

  • 可通过 test 命令对脚本进行语法测试,示例:
    [user@host ~]$ test 1 -ge 0; echo $?
    0
    [user@host ~]$ test 0 -gt 1; echo $?
    1
    
  • 可以使用 Bash 的测试语法 [ <TESTEXPRESSION> ] 来执行测试。
  • Bash 数字比较运算符,示例:
    [user@host ~]$ [ 1 -eq 1 ]; echo $?
    0
    [user@host ~]$ [ 1 -ne 1 ]; echo $?
    1
    [user@host ~]$ [ 8 -gt 2 ]; echo $?
    0
    [user@host ~]$ [ 2 -ge 2 ]; echo $?
    0
    [user@host ~]$ [ 2 -lt 2 ]; echo $?
    1
    [user@host ~]$ [ 1 -lt 2 ]; echo $?
    0
    
符号含义
-eq等于(equal)
-ne不等于(not equal)
-gt大于(greater than)
-lt小于(less than)
-ge大于或等于(greater or equal)
-le小于或等于(less or equal)
  • 字符串比较运算符的使用,示例:
    [user@host ~]$ [ abc = abc ]; echo $?
    0
    [user@host ~]$ [ abc == def ]; echo $?
    1
    [user@host ~]$ [ abc != def ]; echo $?
    0
    
符号含义
===字符串相等
!=字符串不相等
  • Bash 的字符串一元运算符,示例:
    [user@host ~]$ STRING=""; [ -z "$STRING" ]; echo $?
    0
    [user@host ~]$ STRING='abc'; [ -n "$STRING" ]; echo $?
    0
    
运算符含义示例结果
-z "$str"字符串为空"" → ✅$?=0
-n "$str"字符串非空"abc" → ✅$?=0
判断语句含义$? 结果
[ 条件 ]判断条件是否为真0=真, 1=假
[ 2 -lt 3 ]数值比较0
[ abc = def ]字符串比较1
[ -z "$x" ]是否为空字符串0(空时真)

2.4 if/then 条件判断结构

  • Bash 中最简单的条件结构是 if/then 结构,其语法如下:
    if <CONDITION>; then
      <STATEMENT>
      <STATEMENT>
    fi
    
  • 如果满足给定条件,将采取一个或多个操作,如果不满足给定条件,则不采取任何操作,示例:
    [user@host ~]$ systemctl is-active psacct >/dev/null 2>&1
    [user@host ~]$ if [ $? -ne 0 ]; then sudo systemctl start psacct;  fi
    

2.5 if/then/else 结构

  • if/then 结构进一步扩展,以便能根据是否满足条件来采取不同的操作集合,语法如下:
    if <CONDITION>; then
      <STATEMENT>
      <STATEMENT>
    else
      <STATEMENT>
      <STATEMENT>
    fi
    
  • 示例:
    [user@host ~]$ systemctl is-active psacct >/dev/null 2>&1
    [user@host ~]$ if [ $? -ne 0 ]; then \
     sudo systemctl start psacct; \
     else \
     sudo systemctl stop psacct;
     fi
    

2.6 if/then/elif/then/else 结构

  • if/then/else 结构可以进一步扩展以测试多个条件,在满足某个条件时执行不同的操作集合,语法如下:
    if <CONDITION>; then
      <STATEMENT>
      <STATEMENT>
    elif <CONDITION>; then
      <STATEMENT><STATEMENT>
    else
      <STATEMENT>
      <STATEMENT>
    fi
    
  • 在此条件结构中,Bash 将按照显示的顺序测试条件,在发现某个条件成立后,Bash 将执行与该条件相关联的操作,然后跳过条件结构的其余部分,如果所有条件均不成立,Bash 将执行 else 子句中的操作,示例:
    [user@host ~]$ systemctl is-active mariadb >/dev/null 2>&1
    MARIADB_ACTIVE=$?
    [user@host ~]$ sudo systemctl is-active postgresql >/dev/null 2>&1
    POSTGRESQL_ACTIVE=$?
    [user@host ~]$ if [ "$MARIADB_ACTIVE" -eq 0 ]; then
     mysql; \
     elif [ "$POSTGRESQL_ACTIVE" -eq 0 ]; then \
     psql; \
     else \
     sqlite3; \
     fi
    

3. 使用正则表达式匹配文本

3.1 正则表达式

  • 正则表达式使用模式匹配机制查找特定内容。
  • vim、grep 和 less 命令都可以使用正则表达式。
  • Perl、Python 和 C 等编程语言在使用模式匹配条件时,也都会使用正则表达式。
  • 正则表达式自成体系,也就是说,该语言有其自身的语法和规则。

3.2 描述正则表达式

  • 最简单的正则是:行中完全匹配,举例:grep cat /usr/share/dict/words

  • 使用 ^ 表示开头匹配,使用 $ 表示末尾匹配,举例:grep ^cat abc.txtgrep dog$ abc.txt

  • ^cat$ 表示匹配只有 cat 的行,cat开头,cat结尾。

  • c.t 表示匹配:含有 cat、c5t、cQt 这样内容的行。

  • c[aou]t 表示只匹配:cat、cot、cut。

  • c.*t 表示匹配:cat、ct、coat、culvert 等以 c 开头,以 t 结尾的内容。

  • c.\{2\}t 表示匹配 c 开头,t 结尾,中间正好 2 个字符的内容,比如 coat,举例:grep 'c.\{2\}t' /usr/share/dict/words

    . :匹配任意单个字符
    * :匹配前一个符号的“零次或多次”
    也就是说,.* 表示“任意长度的字符串(包括空)

基本语法扩展语法描述
.句点 (.) 匹配任何单个字符。
?几个字符
*前序项匹配零次或多次。
+对前序项匹配一次或多次。
{\n}{n}对前序项匹配恰好 n 次。

3.3 通过 grep 匹配

  • grep 命令后跟一个正则表达式和一个文件,示例:
    [user@host ~]$ grep 'computer' /usr/share/dict/words
    computer
    computerese
    computerise
    computerite
    computerizable
    computerization
    computerize
    computerized
    computerizes
    computerizing
    computerlike
    computernik
    computers
    
  • 由于正则表达式常含有 shell 元字符(如 $、* 和 {}),建议使用单引号括起正则表达式。
  • 通过竖线运算符(|),grep 命令可与其他命令一起使用,示例:
    [root@host ~]# ps aux | grep chrony
    chrony     662  0.0  0.1  29440  2468 ?        S    10:56   0:00 /usr/sbin/chronyd
    
元字符Shell 中 的意义正则中 的意义解决办法
*通配符:匹配文件名任意长度前一个字符重复 0 次或多次用引号 'c.*t'
$取变量值(如 $HOME匹配行尾用单引号 'abc$'
{}花括号扩展 {1,2}限定重复次数 {2,5}在基本正则中要写成 \{2,5\}
[]Shell 通配符集 [abc]正则字符集 [abc]都一样,但仍建议加引号
()子 Shell、命令分组正则分组(在 ERE)\( \)-E
``管道符正则“或”运算
?通配符(单字符)前一字符重复 0 或 1 次用引号
\转义符转义符在 Shell 中要写两次 \\

3.4 grep 选项

选项功能
-i使用所提供的正则表达式,但不会强制区分大小写(运行不区分大小写的操作)
-v仅显示不包含正则表达式匹配项的行,取反,不匹配
-r将递归地匹配正则表达式的数据搜索应用到一组文件或目录中
-A NUMBER显示正则表达式匹配项之后的行数
-B NUMBER显示正则表达式匹配项之前的行数
-e如果使用多个 -e 选项,则可以提供多个正则表达式,并将与逻辑 OR 一起使用
  • 示例 1:
    [user@host ~]$ grep -i serverroot /etc/httpd/conf/httpd.conf
    # with "/", the value of ServerRoot is prepended -- so 'log/access_log'
    # ServerRoot at a non-local disk, be sure to specify a local disk on the
    # with ServerRoot set to '/www' will be interpreted by the
    # ServerRoot: The top of the directory tree under which the server's
    # same ServerRoot for multiple httpd daemons, you will need to change at
    ServerRoot "/etc/httpd"
    
  • 示例 2:
    [user@host ~]$ grep -v -i server /etc/hosts
    127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
    ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
    172.25.254.254 classroom.example.com classroom
    172.25.254.254 content.example.com content
    172.25.254.254 materials.example.com materials
    172.25.250.254 workstation.lab.example.com workstation
    ### rht-vm-hosts file listing the entries to be appended to /etc/hosts
    172.25.250.254 workstation.lab.example.com workstation
    
  • 示例 3:
    [user@host ~]$ grep -v '[#;]' /etc/ethertypes
    0800  ip      IPv4
    0805  X25
    0806  arp     ARP
    0808  FR_ARP  #Frame Relay ARP [RFC1701]
    # Internet IP (IPv4)
    ip4     0800
    ether-arp 0806
    

‘[#;]’ 是一个正则字符类
[…] 表示“匹配方括号中任意一个字符”
[ # ; ] 表示匹配:
#(井号)或 ;(分号)
也就是:
“匹配任何包含 # 或 ; 的行”

grep -v 的意思是:
显示 不包含 正则匹配内容的行。
也就是排除掉含有 # 或 ; 的行。

/etc/ethertypes 是系统文件

/etc/ethertypes 通常包含 以太网协议类型编号

  • 示例 4:
    [root@host ~]# cat /var/log/secure | grep -e 'pam_unix' -e 'user root' -e 'Accepted publickey' | less
    Mar 19 08:04:46 jegui sshd[6141]: pam_unix(sshd:session): session opened for user root by (uid=0)
    Mar 19 08:04:50 jegui sshd[6144]: Disconnected from user root 172.25.250.254 port 41170
    Mar 19 08:04:50 jegui sshd[6141]: pam_unix(sshd:session): session closed for user root
    Mar 19 08:04:53 jegui sshd[6168]: Accepted publickey for student from 172.25.250.254 port 41172 ssh2: RSA SHA256:M8ikhcEDm2tQ95007vufqEixcFct+WOwZLNZN1BTO
    
  • 在 vim 或 less 命令中进行搜索时,输入 / 字符,然后键入搜索内容,按 Enter 开始搜索,按 N 查找下一个匹配项,示例:
    [root@host ~]# vim /var/log/boot.log
    ...output omitted...
    [[0;32m  OK  [0m] Finished [0;1;39mdracut pre-pivot and cleanup hook[0m.
    [[0;32m  OK  [0m] Stopped target [0;1;39mRemote Encrypted Volumes[0m.
    [[0;32m  OK  [0m] Starting [0;1;39mCleaning Up and Shutting Down Daemons[0m...
    [[0;32m  OK  [0m] Stopped target [0;1;39mTimer Units[0m.
    [[0;32m  OK  [0m] Closed [0;1;39mSystem Message Bus Socket[0m.
    ...Daemons
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值