[ Content contribution] 基于deepin的shell编程-5.2cut列提取-shell逻辑控制
Tofloor
poster avatar
TIANGESEC工作室
deepin
2023-12-30 01:42
Author

cut 列提取

cut连接文件并打印到标准输出设备上

补充说明

cut命令 用来显示行中的指定部分,删除文件中指定字段。cut经常用来显示文件的内容,类似于下的type命令。

说明:该命令有两项功能,其一是用来显示文件的内容,它依次读取由参数file所指 明的文件,将它们的内容输出到标准输出上;其二是连接两个或多个文件,如cut fl f2 > f3将把文件fl和几的内容合并起来,然后通过输出重定向符“>”的作用,将它们放入文件f3中。

当文件较大时,文本在屏幕上迅速闪过(滚屏),用户往往看不清所显示的内容。因此,一般用more等命令分屏显示。为了控制滚屏,可以按Ctrl+S键,停止滚屏;按Ctrl+Q键可以恢复滚屏。按Ctrl+C(中断)键可以终止该命令的执行,并且返回Shell提示符状态。

语法

cut(选项)(参数)

选项

 -b:仅显示行中指定直接范围的内容;
 -c:仅显示行中指定范围的字符;
 -d:指定字段的分隔符,默认的字段分隔符为“TAB”;
 -f:显示指定字段的内容;
 -n:与“-b”选项连用,不分割多字节字符;
 --complement:补足被选择的字节、字符或字段;
 --out-delimiter=<字段分隔符>:指定输出内容是的字段分割符;
 --help:显示指令的帮助信息;
 --version:显示指令的版本信息。

 例如有一个学生报表信息,包含ID、Name、age、gender:
 zql@zql-PC:~$ cat student.txt 
 ID      Name    gender  age
 1       zql     M       19
 2       tr      M       19
 3       kgm     M       21
 4       Lisa    W       19
 
 zql@zql-PC:~$ cut -f 2 student.txt 
 Name
 zql
 tr
 kgm
 Lisa
 zql@zql-PC:~$ grep -v "Name" student.txt  | cut -f 2
 zql
 tr
 kgm
 Lisa
 zql@zql-PC:~$ grep -v "Name" student.txt  | cut -f 2,4
 zql     19
 tr      19
 kgm     21
 Lisa    19
 zql@zql-PC:~$ cut -f 2,3 student.txt 
 Name    gender
 zql     M
 tr      M
 kgm     M
 Lisa    W

注意:

cut命令不会识别空格

shell逻辑控制

6.1 if-then语句

shell之中的逻辑控制语句if-then和其他语言的逻辑控制语句不太一样,他的语法结构是这样的:

语法1

 if commend
 then
     commands
 fi

这结构是不是焕然一新,if语句之后的是一个等式,正常情况下其求值的结果是True和False,但是shell里面不是这样的,当在shell中if语句回运行if之后的命令,如果该命令的****退出码为0,命令将会成功地运行,then部分部分的命令就会被执行,如果该命令的状态码为其他的值,那么then部分的命令将不会执行,也就是说控制if-then的是退出码。

文件test1.sh

 #!/bin/bash
 
 if pwd
 then
     echo "Hello Shell!"
 fi

调用脚本

 zql@zql-PC:~$./test.sh
 /home/zql/sh
 Helllo Shell!

可以看见前后两条命令都执行了,如果其中有一个命令错误会发生什么呢?

test1.sh

 #!/bin/bash
 
 if abc
 then
     echo "Hello Shell!"
 fi

掉用脚本

 zql@zql-PC:~$ ./test1.sh
 ./test1.sh: 行 3: abc: 未找到命令

test2.sh

 #!/bin/bash
 
 if pwd
 then
     abc
 fi

调用脚本

 zql@zql-PC:~$ ./test2.sh
 /home/zql/sh
 /home/zql/sh/test2.sh: 行 5: abc: 未找到命令

综上所述:

  • 当命令全部正确的时候即为true的时候,命令能够全部执行
  • 当then前面的命令出现错误的时候,则全为False,命令无法正确执行
  • 当then后面的命令出现错误的时候不会影响钱敏命令的执行

语法2

 if commend; then
     commands
 fi

test3.sh

 #!/bin/bash
 
 if pwd; then
     echo "Hello Linux!"
 fi

执行脚本

 zql@zql-PC:~$ ./test3.sh
 /home/zql/sh
 Hello Linux!

6.2 if-then-else语句

语法

 if commmend
 then
     commands
 else
     commands
 fi

此时的逻辑语句依然受到状态码的控制,当状态码为0的时候就执行then部分的语句,当状态码不为0的时候执行else的语句。

文件testuser.sh

 #!/bin/bash
 #
 if grep $USER /etc/passwd
 then
         echo "是否存在特定的用户?"
         echo "存在特定的用户,这是用户$USER下面的sh文件:"
         echo
         ls $tUSER *.sh
         else
                 echo "这个$USER不存在系统中。"
                 echo
 
 fi
 echo "we are outside the if statement."

执行脚本

 zql@zql-PC:~$ testuser.sh
 zql:x:1000:1000:zql,,,:/home/zql:/usr/bin/zsh
 是否存在特定的用户?
 存在特定的用户,这是用户zql下面的sh文件:
 
 calculate_date.sh  test1.sh  test2.sh  test3.sh  test.sh  testuser.sh
 we are outside the if statement.

if语句的嵌套

shell和其他的语言一样,逻辑结构中可以嵌套多个if

文件test4.sh

 zql@zql-PC:~$ cat test4.sh
 #!/bin/bash
 #
 if grep $USER /etc/passwd
 then
         echo "是否存在特定的用户?"
         echo "存在特定的用户,这是用户下面的sh文件:"
         ls $USER *.sh
         if
                 echo "当前有那些程序在运行?"
         then
                 ps
         fi
         else
                 echo "不存在特定的用户。"
 fi
 
 echo "程序执行完成,退出!"

脚本调用

 zql@zql-PC:~$ ./test4.sh
 zql:x:1000:1000:zql,,,:/home/zql:/usr/bin/zsh
 是否存在特定的用户?
 存在特定的用户,这是用户下面的sh文件:
 ls: 无法访问 'zql': 没有那个文件或目录
 calculate_date.sh  test1.sh  test2.sh  test3.sh  test4.sh  test.sh  testuser.sh
 当前有那些程序在运行?
     PID TTY          TIME CMD
    1092 pts/0    00:00:02 zsh
    1481 pts/0    00:00:00 test4.sh
    1484 pts/0    00:00:00 ps
 程序执行完成,退出!

6.3 elif语句

语法

 if commend
 then commands
 elif commend2
 then commands
 fi

文件test7.sh

 #!/bin/bash
 
 if sudo systemctl start httpd
 then
         echo "HTTP服务成功打开" ; sleep 2
 elif sudo systemctl enable httpd
 then
         echo "HTTP服务已设置开机自启" ; sleep 2
 else
         echo "以上设置失败" ; sleep 1
 fi
 
 if sudo systemctl start mysqld
 then
        echo "mysqld服务成功打开" ; sleep 2
 elif sudo systemctl enable mysqld
 then
         echo "mysqld服务已设置开机自启" ; sleep 2
 else
         echo "以上设置失败" ; sleep 1
 fi
 
 echo "当前http状态"
 systemctl status httpd ; sleep 1
 echo "开机状态"
 systemctl is-enabled httpd ; sleep 1
 
 echo "当前mariadb状态"
 systemctl status mysqld ; sleep 1
 echo "开机状态"
 systemctl is-enabled mysqld ; sleep

脚本运行

 zql@zql-PC:~$ ./test7.sh
 Failed to start httpd.service: Unit httpd.service not found.
 Failed to enable unit: Unit file httpd.service does not exist.
 以上设置失败
 mysqld服务成功打开
 当前http状态
 Unit httpd.service could not be found.
 开机状态
 Failed to get unit file state for httpd.service: No such file or directory
 当前mariadb状态
 ● mariadb.service - MariaDB 10.5.12 database server
      Loaded: loaded (/lib/systemd/system/mariadb.service; disabled; preset: disabled)
      Active: active (running) since Tue 2023-02-21 12:35:09 CST; 3min 1s ago
        Docs: man:mariadbd(8)
              https://mariadb.com/kb/en/library/systemd/
     Process: 1374 ExecStartPre=/usr/bin/install -m 755 -o mysql -g root -d /var/run/mysqld (code=exited, status=0/SUCCE>
     Process: 1375 ExecStartPre=/bin/sh -c systemctl unset-environment _WSREP_START_POSITION (code=exited, status=0/SUCC>
     Process: 1377 ExecStartPre=/bin/sh -c [ ! -e /usr/bin/galera_recovery ] && VAR= ||   VAR=`cd /usr/bin/..; /usr/bin/>
     Process: 1440 ExecStartPost=/bin/sh -c systemctl unset-environment _WSREP_START_POSITION (code=exited, status=0/SUC>
     Process: 1442 ExecStartPost=/etc/mysql/debian-start (code=exited, status=0/SUCCESS)
    Main PID: 1425 (mariadbd)
      Status: "Taking your SQL requests now..."
       Tasks: 9 (limit: 2233)
      Memory: 120.7M
         CPU: 845ms
      CGroup: /system.slice/mariadb.service
              └─1425 /usr/sbin/mariadbd
 ...............             
 开机状态
 alias
 ./test7.sh: 行 31: sleep#!/bin/bash: 没有那个文件或目录

由于我的Linux还未安装http,所以会执行错误。

6.4 利用test命令测试不同的条件

语法

 if test conditon
 then commands
 fi

condition 是test要测试的一系列参数的值。

文件test6.sh

 #!/bin/bash
 #
 if test
 then
         echo "No expression return a True."
         else
                 echo "No expression return a False."
 fi

调用脚本

 zql@zql-PC:~$ ./test6.sh
 No expression return a False.

字符大小写处理

文件test8.sh

 #!/bin/bash
 #
 string1=Score
 string2=score
 
 if [ $string1 \> $string2 ]
 then
         echo "$string1 > $string2"
 else
         echo "$string1 < $string2"
 fi

脚本调用

 zql@zql-PC:~$ ./test8.sh
 Score < score

运行以上脚本,发现大写字母小于小写字母,原因是排序是由字符编码决定大小的。

-n和-z可以方便地用于检查一个变量是否为空。

文件test9.sh

 #!/bin/bash
 #
 #
 string1=Score
 String2=''
 echo "判断字符string1是否为空."
 if [ -n $string1 ]
 then
         echo "字符串$string1不是空的."
 else
         echo "字符串$sting1是空的."
 fi
 sleep 1
 echo "判断字符串string2是否为空."
 if [ -z $string2 ]
 then
         echo "字符串$string2是空的."
 else
         echo "字符串$string2不是空的."
 fi
 sleep 0.1
 echo "Program exit."

脚本调用

 zql@zql-PC:~$ ./test9.sh
 判断字符string1是否为空.
 字符串Score不是空的.
 判断字符串string2是否为空.
 字符串是空的.
 Program exit.

6.5 数值比较与字符串比较

利用test命令可以进行数值比较。

数值比较

比较 描述
n1 -eq n2 测试n1是否等于n2
n1 -ge n2 测试n1是否大于等于n2
n1 -gt n2 测试n1是否大于n2
n1 -le n2 测试n1是否小于等于n2
n1 -lt n2 测试n1是否小于n2
n1 -ne n2 测试n1是否不等于n2

字符比较

比较 描述
str1 = str2 测试str1是否与str2相同
str1 != str2 测试str1是否与str2不同
str1 < str2 测试str1是否小于str2
str1 > str2 测试str1是否大于str2
-n str1 测试str1长度是否不为0
-z str1 测试str1长度是否

6.6 文件比较

选项 功能
-d file 检查file是否存在且为目录
-e file 检查file是否存在
-f file 检查file是否为文件
-r file 检查file是否可读
-s file 检查file是否为空
-w file 检查file是否可写
-x file 检查file是否可执行
-O file 检查file是否存在且属当前用户所有
-G file 检查file是否存在且默认组与当前用户相同
file1 -nt file2 检查file1是否比file2旧
file1 -ot file2 检查file1是否比file2旧

检查目录-d

  • -d测试会检查指定的目录是否存在系统中。

文件test10.sh

 #!/bin/bash
 #
 jump_directory=/home/troy
 
 if [ -d $jump_directory ]
 then
         echo "这$jump_directory目录存在,切换到该目录" ; sleep 0.5
         cd $jump_directory ; sleep 0.5
         echo "查看当前目录的文件" ; sleep 0.5
         ls
 else
         echo "这个$jump_directory目录不存在"
 fi
 echo "Program exit."

执行脚本

 zql@zql-PC:~$ ./test10.sh
 这个/home/troy目录不存在
 Program exit

检查对象是否存在-e

  • -e选项与些许在使用后文件或目录前先检查其是否存在。

文件update-file.sh

 #!/bin/bash
 #
 location=$HOME
 filename="seteinel"
 
 #检查用户目录是否存在
 if [ -d $location ]
 then
         echo "$location在这个目录里." ; sleep 0.5
         echo "文件名是$filename." ; sleep 0.5
         if [ -e $location/$filename ]
         then
                 echo "一个文件,$filename." ; sleep 0.5
                 echo "正在更新文件内容." ; sleep 0.5
                 date >> $location/$filename
         else
                 echo "文件$location/$filename不存在." ; sleep 0.5
                 echo "没有数据更新." ; sleep 0.5
         fi
 else
         echo "目录$location不存在." ; sleep 0.5
         echo "没有数据更新."
 fi

脚本调用

 zql@zql-PC:~$ ./update-file.sh
 /home/zql在这个目录里.
 文件名是seteinel.
 文件/home/zql/seteinel不存在.
 没有数据更新.
  • -f指定文件

文件update-file2.sh的内容

 #!/bin/bash
 #
 location=$HOME/sh
 
 #检查用户目录是否存在
 if [ -d $location ]
 then
         echo  " $location目录/文件存在." ; sleep 0.5
         if [ -f $location ]
         then
                 echo "$location是一个文件." ; sleep 0.5
         else
                 echo "$location是一个目录." ; sleep 0.5
         fi
 else
         echo "$location目录/文件不存在." ; sleep 0.5
 fi

调用脚本

 zql@zql-PC:~$ ./update-file2.sh
  /home/zql/sh目录/文件存在.
 /home/zql/sh是一个目录.

检查是否可读-r

  • -r可以检查文件是否可读

文件readfile.sh

 #!/bin/bash
 #
 #检查文件是否可读
 #
 file=/etc/shadow
 echo
 echo "检查此文件$file是否可读." ; sleep 0.3
 if [ -f $file ]
 then
         if [ -r $file ]
         then
                 echo "显示文件末尾..." ; sleep 0.3
                 tail $file
         else
                 echo "Sorry,文件拒绝读取." ; sleep 0.3
         fi
 else
         echo "文件$file不存在."
 fi

脚本调用

 zql@zql-PC:~$ ./readfile.sh
 
 检查此文件/etc/shadow是否可读.
 Sorry,文件拒绝读取.

检查空文件-s

  • -s检查文件是否为空

文件emptyfile.sh

 #!/bin/bash
 #
 #检查是否是空文件
 #
 filename=$HOME/Documents/file.txt
 echo
 echo "检查文件$filename是否为空?" ; sleep 0.3
 if [ -f $filename ]
 then
         if [ -s $filename ]
         then
                 echo "文件$filename存在,并且存在数据." ; sleep 0.3
                 echo "将不会删除文件." ; sleep 0.3
         else
                 echo "文件$filename存在,但是是空的." ; sleep 0.3
                 echo "删除空文件." ; sleep 0.3
                 rm $filename
         fi
 else
         echo "这$filename文件不存在."
 fi

调用脚本

 zql@zql-PC:~$ ll /home/zql/Documents/
 总计 0
 -rw-r--r-- 1 zql zql 0  2月27日 20:36 file.txt
 
 zql@zql-PC:~$ ./emptyfile.sh
 
 检查文件/home/zql/Documents/file.txt是否为空?
 文件/home/zql/Documents/file.txt存在,但是是空的.
 删除空文件.
 
 #检查文件是否还存在
 zql@zql-PC:~$ ll /home/zql/Documents/
 总计 0

检查是否可写入-w

文件 writefile.sh

 #!/bin/bash
 #
 #检查文件是否可写
 filename=$HOME/Documents/file.txt
 echo
 if [ -f $filename ]
 then
         if [ -w $filename ]
         then
                 echo "尝试写入文件$filename." ; sleep 0.3
                 date +%H%M >> $filename
                 echo "文件$filename写入成功." ; sleep 0.3
         else
                 echo "文件$filename拒绝写入." ; sleep 0.3
         fi
 else
         echo "文件$filename不存在."
 fi

调用脚本

 zql@zql-PC:~$ ./writefile.sh
 
 尝试写入文件/home/zql/Documents/file.txt.
 文件/home/zql/Documents/file.txt写入成功.
 
 zql@zql-PC:~$ cat  /home/zql/Documents/file.txt
 2135
 2136

检查是否可执行-x

文件x-file.sh

 zql@zql-PC:~$ cat x-file.sh
 #!/bin/bash
 #
 #检查文件是否能执行
 filename=$HOME/sh/wirtefile.sh
 echo "你正在尝试执行文件$filename............"
 if [ -x $filename ]
 then
         echo "执行文件中---------------------"
         $filename
 else
         echo "Sorry,你不能运行文件$filename"
 fi

调用脚本

 zql@zql-PC:~$ ./x-file.sh
 你正在尝试执行文件/home/zql/sh/wirtefile.sh............
 Sorry,你不能运行文件/home/zql/sh/wirtefile.sh
 
 zql@zql-PC:~$ ls -l /home/zql/Documents
 总计 4
 -rw-r--r-- 1 zql zql 10  2月27日 21:36 file.txt

检查文件属主-O

  • -O选项的主要作用就是检查你是否是文件的属主。

 #!/bin/bash
 #
 #检查文件的属主
 if [ -O /etc/passwd ]
 then
         echo "You are the owner of the /etc/passwd file."
 else
         echo "Sorry,you are not /etc/passwd file's owner"
 fi

调用脚本

 zql@zql-PC:~$ ./whohost.sh
 Sorry,you are not /etc/passwd file's owner
 
 zql@zql-PC:~$ whoami
 zql
 
 zql@zql-PC:~$ ls -o /etc/passwd
 -rw-r--r-- 1 root 3228  2月16日 10:34 /etc/passwd
 
 #此文件的属主是root用户,自身用户zql不是属主

检查文件属组-G

  • -G检查文件的属组,如果与用户的默认组匹配,测试成功。

 ┌──(zql㉿kali)-[~/sh]
 └─$ cat grouphost.sh
 #!/bin/bash
 #
 echo "检查按文件属组..."
 sleep 0.3
 if [ -G $HOME/sh ]
 then
         echo "文件|目录$HOME/sh 在默认组..." ; sleep 0.3
 else
         echo "Sorry,你默认的分组和$HOME/sh 文件|目录的组是默认的..."
 fi

调用脚本

 zql@zql-PC:~$ ./grouphost.sh
 检查按文件属组...
 文件|目录/home/zql/sh 在默认组...
 
 zql@zql-PC:~$ la -g $HOME/sh
 总计 120
 -rwxr-xr-x 1 zql   186  2月21日 22:00 alterup.sh
 -rwxr-xr-x 1 zql   252  3月 2日 11:36 Booleantest.sh
 -rwxr-xr-x 1 zql   398  2月17日 19:59 calculate_date.sh
 -rwxr-xr-x 1 zql   469  2月27日 21:00 emptyfile.sh
 -rwxr-xr-x 1 zql   229  3月 2日 12:59 grouphost.sh
 -rwxr-xr-x 1 zql    51  2月27日 15:54 marktext.sh
 -rwxr-xr-x 1 zql   314  2月27日 20:14 readfile.sh
 -rwxr-xr-x 1 zql   303  2月23日 21:23 test10.sh
 -rwxr-xr-x 1 zql    51  2月17日 20:33 test1.sh
 ...

检查文件日期-nt与-ot

  • -nt测试会判定一个文件是否比另一个文件更新。如果文件较新,那意味着其文件创建日期更晚。
  • -ot测试会判定一个文件是否比另一个文件更旧。

 zql@zql-PC:~$ cat thandates.sh
 #!/bin/bash
 #
 #比较文件的新旧
 echo "正在检测文件的新旧..."
 if [ $HOME/sh/test1.sh -nt $HOME/Documents/file.txt ]
 then
         echo "文件$HOME/sh/test1.sh 比 $HOME/Documents/file.txt新..."
 else
         echo "文件$HOME/sh/test1.sh 比 $HOME/Documents/file.txt旧..."
 fi
 echo "Progame exit."

调用脚本

 zql@zql-PC:~$ ./thandates.sh
 正在检测文件的新旧...
 文件/home/zql/sh/test1.sh 比 /home/zql/Documents/file.txt旧...
 Progame exit.
 
 zql@zql-PC:~$ ls -l /home/zql/Documents/file.txt
 -rw-r--r-- 1 zql zql 10  2月27日 21:36 /home/zql/Documents/file.txt
 
 zql@zql-PC:~$ ls -l /home/zql/sh/test1.sh
 -rwxr-xr-x 1 zql zql 51  2月17日 20:33 /home/zql/sh/test1.sh

复合条件测试

if-then语句允许布尔逻辑测试。

语法

 commend1&&commend2
 commend1||commend2

 zql@zql-PC:~$ cat Booleantest.sh
 #!/bin/bash
 #
 #符合条件测试
 if [ -d $HOME/Documents/file.txt ] && [ -w $HOME/Documents/file.txt ]
 then
         echo "这个文件存在,并且你有权限修改." ; sleep 0.3
 else
         echo "你不能对文件进行修改,权限不足." ; sleep 0.3
 fi

调用脚本

 zql@zql-PC:~$ ./Booleantest.sh
 你不能对文件进行修改,权限不足.
 
 zql@zql-PC:~$ ls -l /home/zql/Documents
 总计 4
 -rw-r--r-- 1 zql zql 10  2月27日 21:36 file.txt

括号与方括号

单括号

单括号允许if语句使用子shell,在bash shell执行命令之前,会先船舰一个子shell,然后再其中执行命令。如果命令成功结束,就会有个退出状态码,只有状态码为0的时候,if语句的then部分才会执行。

 zql@zql-PC:~$$ cat test11.sh
 #!/bin/bash
 #
 echo "测试单括号..."
 echo $BASH_SUBSHELL
 if (echo $BASH_SUBSHELL)
 then
         echo "The subshell command operated successfully." ; sleep 0.2
 else
         echo "The subshell command was not successfull." ; sleep 0.2
 fi
 echo "Programe exit."

调用脚本

 zql@zql-PC:~$ ./test11.sh
 测试单括号...
 0
 1
 The subshell command operated successfully.
 Programe exit.

注意第一次使用echo $BASH_SUBSHELL是再当前的shell中执行的,当进入if语句后执行的就是子shell。所以第一次输出的是0,第二次输出的是1。

注意:

当你在if test语句中使用进程列表时,可能会出现意料之外的结果。哪怕进程列表中除最后一个命令之外的其他命令全都失败,子shell仍会将退出状态码设为0,then部分的命令将得以执行。

双括号

双括号命令允许在比较过程中使用高级数学表达式。test命令在进行比较的时候只能使用简单的算术操作。

符号 作用
value++ 后增
value-- 后减
++value 先增
--value 先减
逻辑求反
~ 位求反
** 幂运算
<< 左位移
>> 右位移
& 位布尔and
&& 逻辑and

双方括号

双方括号命令提供了针对字符串比较的高级特性。双方括号的格式如下:

 [[ expression ]]

expression可以使用test命令中的标准字符串比较。除此之外,它还提供了test命令所不具备的另一个特性——模式匹配。

注意 双方括号在bash shell中运行良好。不过要小心,不是所有的shell都支持双方括号。

6.7 case语句

语法

 case 变量 in
 pattern1 | pattern2) commands1;;
 pattern3) commands2;;
 *) default commands;;

case命令会将指定变量与不同模式进行比较。如果变量与模式匹配,那么shell就会执行为该模式指定的命令。你可以通过竖线运算符在一行中分隔出多个模式。星号会捕获所有与已知模式不匹配的值。

说实话这case语句是真的复杂,我还不如直接if-else

Reply Favorite View the author
All Replies

No replies yet