二维码

bash 指令连续下达与数据流重导向

830 人阅读 | 时间:2021年12月17日 23:31

8.1:连续指令的下达

某些情况下,用户可能会连续的进行某些指令的下达。 但这些指令之间可能会有关连性,例如前一个指令成功后才可进行下一个指令等。 这些情况就需要使用到特殊的字符来处理。

8.1.1:指令回传值

前面的章节我们一直使用到bash终端环境下的指令操作,而且一直接触到很多的单引号、双引号、钱字号、反单引号、大括号、小括号等等,其实在该成对的符号内,隐藏了:指令、变量、计算式等的功能! 再次了解特殊的符号的用途,请完成底下的练习:

例题 8.1.1-1: 请将'变量'、'指令'、'数学计算式'、'纯文字'、'保持 $ 功能'等写入下方的空格中
  1. var=${     }

  2. var=$(     )

  3. var=$((     ))

  4. var="     "

  5. var='     '

  6. var=`     `

接下来,直接应用一下上面的功能:

例题 8.1.1-2: 请找出 ifconfig 与 chfn 等指令后,列出该指令的权限
  1. 先以 which command 的方式找出指令的全名

  2. 将上述的结果,使用 ls -l 显示出来。 请搭配前一个例题的符号 ($, ', ", ' 等) 来处理。

指令的执行正确与否与后续的处理有关。 Linux 环境下默认的指令正常结束回传值为 0 ,呼叫的方式为使用' echo $? 』 即可, 亦即找出 ? 这个变数的内容即可。

例题 8.1.1-3:了解各指令回传值的意义
  1. 输入『 /etc/passwd 』这个文件名在指令列,之后再输入『 echo $? 』 观察输出的号码为何?

  2. 输入『 vbirdcommand 』这个指令名,之后再输入『 echo $? 』 观察输出的号码为何?

  3. 因为尚未进入其他指令(上述两个文件名、指令都是不正确的),因此这些错误讯息应该来自于bash本身的判断。 因此使用' man bash '后,查询『 ^exit status '关键词,找出上述号码的意义为何?

  4. 承上,该段文字叙述中,解释的回传值共有几个号码?

  5. 输入『 ls /vbird ',之后观察输出的回传值,查询该回传值的意义为何? (你应该要 man ls 还是 man bash 呢? )

上述的练习在让用户了解到,指令回传值是每个指令自己指定的,只要符合 bash 的基本规范即可。

8.1.2:连续指令的下达

命令是可以连续输入的,直接通过分号(;) 隔开每个指令即可。 在没有依赖的命令环境中,可以直接进行如下的行为:

  • 列出目前的日期,直接使用 date 即可;

  • 使用 uptime 列出当前系统信息;

  • 列出核心信息;

[student@localhost ~]$ date; uptime; uname -r日  4月 19 15:22:43 CST 2020
 15:22:43 up 48 min,  2 users,  load average: 0.00, 0.00, 0.00
4.18.0-147.el8.x86_64

如此一口气就可以直接将所有的指令执行完毕,无须考量其他问题。 当用户有多个指令需要下达,每个指令又需要比较长的等待时间时, 可以使用这种方式来处理即可。 但是,如果想要将这些信息同步输出到同一个档案时,应该如何处理? 参考底下两个范例后,说明其差异为何?

例题 8.1.2-1: 使用大括号将数据汇整的功能

请使用底下的两个指令处理数据流,探讨其原因

[student@localhost ~]$ date; uptime; uname -r > myfile.txt[student@localhost ~]$ (date; uptime; uname -r ) > myfile.txt
  • 具有指令相依性的 && ||

分号 (;) 是直接连续下达指令,指令间不必有一定程度的相依性。 但当指令之间有相依性时,就能够使用 && 或 || 来处理。 这两个处理的方式如下:

  • command1 && command2
    当 command1 执行回传为 0 时(成功),command2 才会执行,否则就不执行。

  • command1 || command2
    当 command1 执行回传为非 0 时(失败),command2 才会执行,否则就不执行。

实际练习: 当不存在 /dev/shm/check 时,就建立该目录,若已经建立该目录,就不做任何动作。
解析:这题虽然可以使用『 mkdir -p /dev/shm/check '来动作,不过,如果担心文件名指定错误而造成某些困扰, 那还是依据测试的结果来进行目录的建置比较好,尽量减少使用『 mkdir -p '的运用。 我们假设该目录的检查为使用 ls 检测即可。 当 ls /dev/shm/check 显示错误时,表示该文件名不存在,此时才使用 mkdir (不要加上 -p 的选项) 来处理。 第一次执行时,由于尚未有该目录,所以显示找不到,但是第二次执行时,就会有该目录,因此 mkdir 的动作就没有进行。 若将中间分隔改为分号 (;) 时,就会产生重复 mkdir 的问题了。 因此,比较好的执行方式,还是需要使用 || 较佳!
[student@localhost ~]$ ls -ld /dev/shm/checkls: 無法存取 '/dev/shm/check': 沒有此一檔案或目錄# 確認該檔名是不存在的![student@localhost ~]$ ls -ld /dev/shm/check || mkdir /dev/shm/checkls: 無法存取 '/dev/shm/check': 沒有此一檔案或目錄
[student@localhost ~]$ ls -ld /dev/shm/checkdrwxrwxr-x. 2 student student 40  4月 19 16:26 /dev/shm/check# 檔案出現了!這是因為 mkdir 的緣故![student@localhost ~]$ ls -ld /dev/shm/check || mkdir /dev/shm/checkdrwxrwxr-x. 2 student student 40  4月 19 16:26 /dev/shm/check# 再次運作也不會出現 mkdir 的錯誤! || 會略過正確訊息的動作!
实际练习:当 /dev/shm/check 存在时,就将该目录删除,否则就不进行任何动作
解析:跟前面一题差不多,但是这里是'有该目录时,就给予删除',所以反而是'前面指令成功时,后面指令才运作'的概念。 与前一个例题相似,透过 ls 简易的进行搜寻的任务,读者也同样会发现两次执行的结果并不相同。 此外,最后一个指令也能够让读者知道, && 与 ; 的差异!
[student@localhost ~]$ ls -ld /dev/shm/check && rmdir /dev/shm/checkdrwxrwxr-x. 2 student student 40  4月 19 16:26 /dev/shm/check# 兩個指令都分別順利運作完畢[student@localhost ~]$ ls -ld /dev/shm/check && rmdir /dev/shm/checkls: 無法存取 '/dev/shm/check': 沒有此一檔案或目錄# 第一個 ls 的指令失敗,因此並沒有執行 rmdir 喔!若不信,使用底下指令看看:[student@localhost ~]$ ls -ld /dev/shm/check ; rmdir /dev/shm/checkls: 無法存取 '/dev/shm/check': 沒有此一檔案或目錄
rmdir: failed to remove '/dev/shm/check': 沒有此一檔案或目錄

假设我们需要一个指令来说明某个文件名是否存在,可以这样处理:

[student@localhost ~]$ ls -d /etc && echo exist || echo non-exist/etc
exist
[student@localhost ~]$ ls -d /vbird && echo exist || echo non-existls: 無法存取 /vbird: 沒有此一檔案或目錄
non-exist

由于我们只是想要知道该档案是否存在,因此不需要如上表所示,连 ls 的结果也输出。 此时可以使用 &> 的方式来将结果输出到垃圾桶,如下所示:

[student@localhost ~]$ ls -d /etc &> /dev/null && echo exist || echo non-existexist
[student@localhost ~]$ ls -d /vbird &> /dev/null && echo exist || echo non-existnon-exist
例题 8.1.2-2:了解连续指令的逻辑问题
上述的指令能否写成:' ls -d /vbird &> /dev/null || echo non-exist && echo exist ',尝试说明原因。
  • 尝试自行撰写小程序

由于上述指令要修改很麻烦,假设我们需要使用' checkfile filename '来处理,此时可以撰写一只小脚本来进行此任务。 若该指令可以让所有用户执行,则可将指令写入 /usr/local/bin 目录内。

[root@localhost ~]# vim /usr/local/bin/checkfile#!/bin/bash
ls -d ${1} &> /dev/null && echo "${1} exist" || echo "${1} non-exist"[root@localhost ~]# chmod a+x /usr/local/bin/checkfile[root@localhost ~]# checkfile /etc/etc exist
[root@localhost ~]# checkfile /vbird/vbird non-exist

在 checkfile 文件中,第一行 (#!/bin/bash) 代表使用 bash 来执行底下的语法,第二行当中的变量 ${1} 代表在本档案后面所接的第一个参数,因此执行时,就能够直接将要判断的文件名接在 checkfile 后面即可。

8.1.3:使用 test 及 [ 判断式 ] 确认回传值

事实上,前一小节使用 ls 进行确认文件名时,仅需要确认回传值是否为 0 而已。 Linux 提供一个名为 test 的命令可以确认许多文件名参数, 常见的参数有:

测试的标志代表意义
1. 关于某个文件名的'文件类型'判断,如 test -e filename 表示存在否
-e该'文件名'是否存在? (常用)
-f该'文件名'是否存在且为档案(file)? (常用)
-d该'文件名'是否存在且为目录(directory)? (常用)
-b该'文件名'是否存在且为一个 block device 装置?
-c该'文件名'是否存在且为一个 character device 装置?
-S该'文件名'是否存在且为一个 Socket 档案?
-p该'文件名'是否存在且为一个 FIFO (pipe) 文件?
-L该'文件名'是否存在且为一个链接文件?
2. 关于文件的权限检测,如 test -r filename 表示可读否 (但 root 权限常有例外)
-r侦测该文件名是否存在且具有'可读'的权限?
-w侦测该文件名是否存在且具有'可写'的权限?
-x侦测该文件名是否存在且具有'可执行'的权限?
-u侦测该文件名是否存在且具有'SUID'的属性?
-g侦测该文件名是否存在且具有'SGID'的属性?
-k侦测该文件名是否存在且具有'Sticky bit'的属性?
-s侦测该文件名是否存在且为'非空白档案'?
3. 两个文件之间的比较,如: test file1 -nt file2
-nt(newer than)判断 file1 是否比 file2 新
-ot(older than)判断 file1 是否比 file2 旧
-ef判断 file1 与 file2 是否为同一档案,可用在判断 hard link 的判定上。 主要意义在判定,两个档案是否均指向同一个 inode 哩!
4. 关于两个整数之间的判定,例如test n1 -eq n2
-eq两数值相等(equal)
-ne两数值不等(not equal)
-gtn1 大於 n2 (greater than)
-ltn1 小於 n2 (less than)
-gen1 大于等于 n2 (greater than or equal)
-len1 小於等于 n2 (less than or equal)
5. 判定字符串的数据
test -z string判定字符串是否为 0 ? 若 string 为空字串,则为 true
test -n string判定字符串是否非为 0 ? 若 string 为空字串,则为 false。
注: -n 亦可省略
test str1 == str2判定 str1 是否等于 str2 ,若相等,则回传 true
test str1 != str2判定 str1 是否不等于 str2 ,若相等,则回传 false
6. 多重条件判定,例如: test -r filename -a -x filename
-a(and)两状况同时成立! 例如 test -r file -a -x file,则 file 同时具有 r 与 x 权限时,才回传 true。
-o(or)两状况任何一个成立! 例如test-rfile-o-x file,则file具有rax权限时,就可回传true。
!反相状态,如 test ! -x file ,当 file 不具有 x 时,回传 true

test 仅会回传 $? 而已,屏幕上不会出现任何的变化,因此如果需要取得回应,就需要使用 echo $? 的方式来查询, 或者使用 && 及 || 来处理。

例题 8.1.3-1: 学习使用 test 指令判断
  1. 使用 test 判断 /etc/ 是否存在,然后显示回传值

  2. 使用 test 判断 /usr/bin/passwd 是否具有 SUID ,然后显示回传值

  3. 使用 test 判断 ${HOSTNAME} 是否等于 "mylocalhost" ,然后显示回传值

  4. 修改 /usr/local/bin/checkfile ,取消 ls 的判断,改用 test 判断

  • 使用中括号 [] 取代 test 进行判别式的处理

由于 test 是直接加在变量判断之前,读者可能偶而会觉得怪异。 此时可以使用中括号 [] 来取代 test 的语法。 同样以 checkfile 来处理时,该文件的内容应该需要改写成如下:

[root@localhost ~]# vim /usr/local/bin/checkfile#!/bin/bash[ -e "${1}" ] && echo "${1} exist" || echo "${1} non-exist"

由于中括号的意义非常多,包括第三堂课万用字符当中,中括号代表的是'具有一个指定的任意字符',未来第九堂课的正规表示法当中, 中括号也具有特殊的字符意义。 而分辨是否为'判别式'的部份,就是其语法的差别。 请注意,在 bash 环境下,使用中括号替代 test 指令时, 中括号的内部需要留白一个以上的空白字符! 如下图标:

[  "$HOME"  ==  "$MAIL"  ]
[□"$HOME"□==□"$MAIL"□]
 ↑       ↑  ↑       ↑
例题 8.1.3-2:使用 [] 取代 test 的用法
  1. 使用 [ ] 判断 /etc/ 是否存在,然后显示回传值

  2. 使用 [ ] 判断 /usr/bin/passwd 是否具有 SUID ,然后显示回传值

  3. 使用 [ ] 判断 ${HOSTNAME} 是否等于 "mylocalhost" ,然后显示回传值

  • 自定义回传值意义

如果用户想要使用简易的 shell script 创立一个指令,也能够自己设定回传值的意义。

[root@localhost ~]# vim /usr/local/bin/myls.sh#!/bin/bash
ls ${@} && exit 100 || exit 10[root@localhost ~]# chmod a+x /usr/local/bin/myls.sh[student@localhost ~]$ myls.sh /vbird; echo $?ls: 無法存取 '/vbird': 沒有此一檔案或目錄10

上述的 ${@} 代表指令后面接的任何参数,因此你可以执行 myls.sh 后面接多个参数都没问题。 由于 exit 可以回传讯息,因此可以让用户简易的设置好所需要的回传讯息规范。

8.1.4:命令别名

第一堂课开始读者应该就接到到 ls 与 ll 这两个指令,刚开始介绍时,读者们应该知道 ll 是 long list 的缩写。 若将 ll 这个指令用来取代 checkfile 这个脚本,是否可以处理?

[root@localhost ~]# vim /usr/local/bin/checkfile#!/bin/bash
#[ -e "${1}" ] && echo "${1} exist" || echo "${1} non-exist"ll -d ${1} && echo "${1} exist" || echo "${1} non-exist"[root@localhost ~]# checkfile /etc/usr/local/bin/checkfile: 列 5: ll:命令找不到
/etc non-exist

但是,当你执行 checkfile /etc 时,竟然出现 command not found 的问题! 这是为什么? 因为系统上真的没有 ll 这个指令, 该指令为使用命令别名暂时创造出来的一个命令的别称 (别名) 而已。 若你在 root 的身份输入 alias 与在 student 的身份输入 alias, 那就会得到两个不同身份的命令别名了:

[root@localhost ~]# aliasalias cp='cp -i'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'     <==指令別名!alias ls='ls --color=auto'
alias mv='mv -i'
alias rm='rm -i'
......

[student@localhost ~]$ aliasalias cp='cp -i'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias mv='mv -i'
alias rm='rm -i'
alias vi='vim'                    <==跟 root 比,多出來的!......

因此读者应该能知道为何 /bin/ls -d /etc 与 ls -d /etc 输出的结果会有颜色差异的问题了。 此外,管理员执行 mv, cp, rm 等管理文件的指令时, 为了避免不小心导致的文件覆盖等问题,于是仅有 root 的身份会加上 -i 的选项,提示管理员相关的档案覆盖问题。 同时,管理员的 vi 与 vim 默认是不同的软件~一般帐号的 vi 与 vim 则通通是 vim 啊!

例题 8.1.4-1:了解命令别名以及略过命令别名的方案
  1. 使用 root 的身份切换路径到 /dev/shm 底下,并将 /etc 整个目录复制到 '本目录'底下

  2. 若将上述指令重新执行一次,会发生什么问题?

  3. 如果您确定文件名就是需要覆盖,那可以使用什么方式来处理 (思考 A. 使用绝对路径不要用命令别名 B. 让指令自动忽略命令别名)

让指令不以命令别名的方式执行是相当值得注意的喔! 很有趣!

例题 8.1.4-2: 让一般帐号同样具有加上档案覆盖时的询问功能
  1. 由于我们的 student 帐号也算管理员常用的帐号,因此建议也将 cp, mv, rm 默认加上 -i 的选项。 请问如何处理?

8.1.5:用 () 进行数据汇整

某些时刻管理器可能需要进行一串指令后,再将这串指令进行数据的处理,而非每个指令独自运作。 如下行命令的帮助:

[student@localhost ~]$ date; cal -3; echo "The following is log"[student@localhost ~]$ date; cal -3; echo "The following is log" > mylog.txt[student@localhost ~]$ cat mylog.txt

读者会发现到,原本想要纪录的信息当中,仅有最后一个指令才可以被处理了。 若需要每个指令都进行纪录,依据前面的介绍,则必须要如此处理:

[student@localhost ~]$ date > mylog.txt; cal -3 >> mylog.txt; echo "The following is log" >> mylog.txt

指令会变得相当复杂。 此时,可以通过数据统整的方式,亦即将所有的指令包含在小括号内,就能够将讯息统一输出了。

[student@localhost ~]$ (date; cal -3; echo "The following is log") > mylog.txt
例题 8.1.5-1:理解使用 () 处理资料的汇整
  1. 设定一个命令别名为 geterr,内容为执行 echo "I am error" 1>&2

  2. 执行 geterr 得到什么结果?

  3. 执行 geterr 2> /dev/null 得到什么结果?

  4. 执行 (geterr) 2> /dev/null 得到什么结果?

  5. 尝试解析为何会这样?

8.2:数据流重导向

某些时刻用户可能需要将屏幕的信息转存成为档案以方便纪录,就是前几堂课就已经谈到过得>这个符号的功能。 事实上,这个功能就是数据流重导向。

8.2.1:指令执行数据的流动

从前一小节的说明,读者可以知道指令执行后,至少可以输出正确与错误的数据 ($? 是否为 0), 某些指令执行时,则会从文件取得数据来处理,例如 cat, more, less 等指令。 因此,将命令对于数据的装入和输出汇整如下图:

bash 指令连续下达与数据流重导向
图 8.2.1-1、指令执行过程的数据传输情况
  • standard output 与 standard error output

简单的说,标准输出指的是'指令执行所回传的正确的讯息',而标准错误输出可理解为' 指令执行失败后,所回传的错误讯息'。 不管正确或错误的数据都是默认输出到屏幕上,我们可以通过特殊的字符来进行数据的重新导向!

  1. 标准输入 (stdin) :代码为 0 ,使用 < 或 << ;

  2. 标准输出 (stdout):代码为 1 ,使用 > 或 >> ;

  3. 标准错误输出(stderr):代码为 2 ,使用 2> 或 2>> ;

例题 8.2.1-1: 理解资料流的功能
  1. 以 student 身份执行找档名的任务,指令为『 find /etc -name '*passwd*' ',屏幕输出什么信息? 请了解 * 的意义。

  2. student 对于系统配置文件原本就有很多的无权限目录,因此请将错误讯息直接丢弃 ( 导向于 /dev/null )

  3. 将最终屏幕的输出转存成为 ~student/find_passwd.txt 文件

  4. 再以 student 的身份重新搜寻 /etc 底下文件名为 *shadow* 的数据,将正确消息'累加'到 ~student/find_passwd.txt 档案内

  5. 查看 ~student/find_passwd.txt 文件内是否同时具有 passwd 与 shadow 相关的文件名存在?

上述的例题练习完毕后,可以将特殊的字符归类成:

  • 1> :以覆盖的方法将'正确的数据'输出到指定的文件或设备上;

  • 1>>:以累加的方法将'正确的数据'输出到指定的文件或设备上;

  • 2> :以覆盖的方法将'错误的数据'输出到指定的文件或设备上;

  • 2>>:以累加的方法将'错误的数据'输出到指定的文件或设备上;

一般来说,文件无法让两个程序同时打开还同时进行读写! 因为这样数据内容会反复的被改写掉,所以你不应该使用如下的方式来下达指令:

command > file.txt 2> file.txt

如果你需要将正确数据和错误数据同步写入同一个文件内,那就应该要这样思考:

  • 将错误数据转到正确数据的管线上,然后同步输出

  • 将正确数据转到错误数据的管线上,然后同步输出

  • 全部数据通通按序同步输出( 无效和错误)

若同样使用' find /etc -name '*passwd*' '这个指令来处理,则读者可以尝试使用底下的方案来执行上述三个数据转管道的动作:

[student@localhost ~]$ find /etc -name '*passwd*' >   ~/find_passwd2.txt 2>&1[student@localhost ~]$ find /etc -name '*passwd*' 2>  ~/find_passwd2.txt 1>&2[student@localhost ~]$ find /etc -name '*passwd*' &>  ~/find_passwd2.txt

但请注意指令的输入顺序, 2>&1 与 1>&2 必须要在指令的后面输入才行。

  • standard input

有些指令在执行时,你需要敲击键盘才行,这个 standard input 就可以由档案内容来取代键盘输入的意思。 举例来说,cat这个指令就是直接让你敲击键盘来由屏幕输出信息。

例题 8.2.1-2: 测试标准输入
  1. 直接用 student 身份执行' cat '这个指令,然后随意输入两串文字,查阅指令执行的结果为何?

  2. 要结束指令的输入请执行 [ctrl]+d 结束 (并不是 [ctrl]+c 喔! )

  3. 若输入的字符串可以直接转存成为 mycat.txt 文件,该如何下达指令?

  4. 将 /etc/hosts 通过 cat 读入 (使用两种方式,直接读入与通过 < 方式读入)

  5. 将 /etc/hosts 通过 cat 以 < 的方式读入后,累加输出到 mycat.txt 文件内

上面的例题中,我们可以透过 [ctrl]+d 的方式来结束输入,但是一般用户可能会看不懂 [ctrl]+d 代表的意义是什么。 如果能够使用 end 或 eof 等特殊关键词来结束输入,那似乎更为人性化一些。 你可以使用下面的指令来处理:

[student@localhost ~]$ cat > yourtype.txt << eof> here is GoGo!
> eof

最后一行一定要完整的输入 eof (上面的范例),这样就能够结束 cat 的输入,这就是 << 的意义~

8.2.2:管线 (pipe) | 的意义

读者在前几堂课曾经看过类似' ll /etc | more 』的指令,较特别的是管线 (pipe, |) 的功能。 管线的意思是, 将前一个指令的标准输出作为下一个指令的标准输入来处理! 流程有点像底下这样的图标:

bash 指令连续下达与数据流重导向
图 8.2.2-1、管线命令处理示意图

另外,这个管道命令' | ' 仅能处理经由前面一个指令传来的正确信息,也就是 standard output 的信息,对于 stdandard error 并没有直接处理的能力。 如果你需要处理 standard error output ,就得要搭配 2>&1 这种方式来处理才行了。

  • 管线仅会处理 standard output,对于 standard error output 会予以忽略

  • 管线命令必须要能够接受来自前一个指令的数据成为 standard input 继续处理才行。

常见的管道命令有:

  • cut :裁切资料,包括通过固定符号或者是固定字符位置

  • grep :撷取特殊关键词的功能

  • awk '{print $N}' :以空白为间隔,印出第 N 个字段的项目

  • sort :进行资料排序

  • wc :计算数据的行数、字数、字符数

  • uniq :数据依行为单位,进行重复数据的计算

  • tee :将数据转存一份到文件中

  • split :将数据依据行数或容量数切割成数份

例题 8.2.2-1:我想要查看 /etc 底下共有多少档案文件名结尾为 .conf 的档案个数,该如何处理?
  1. 找出文件名最好使用 find 来处理,因此请使用 find /etc 来查看一下资料

  2. 你可以透过' find /etc -name '*.conf' '或' find /etc | grep '\.conf' 』来找到所需要的文件名。 由于grep可以加上颜色显示,故建议可以尝试使用grep的方式来显示较佳。

  3. 最终计算档案数,就可以使用 wc 这个指令来处理' find /etc | grep '\.conf' | wc -l 』

建议用户可以 man wc 看一下该指令的选项功能喔!

例题 8.2.2-2: 使用管线命令
  1. 在 /etc/passwd 里面的第一栏位为账号名称,第七字段为 shell ,我想要只找这两个项目来输出,该如何处理?

  2. 承上,若我只想要知道有多少个 shell (第七字段),同时每个 shell 各有几个,又可以如何处理?

  3. 使用 last 可以查看到每个用户的登录情况,请通过 cut 取出第一个字段后,分析每个帐号的登录次数为何

  4. 使用 ip addr show 可以查询到每个网络界面的 IP 地址,若只想要取出 IPv4 的地址,应该如何处理?

  5. 承上,若只想要列出 IP 地址 (127.0.0.1/8 之类的),是否可以通过 awk 来达成?

  6. 承上,将取得的 IP 地址除了显示在屏幕上,亦同步输出到 /dev/shm/myip.txt 文件中。

8.3:课后练习操作

  • 上课的课后练习,非作业:

  1. 简单的操作底下的题目练习:

    1. 21世纪从2000到2099年,这100年当中,每四年有一次闰年,因此有1/4亦即25年有闰年(366天)。 请用 bash 的整数运算功能,直接算出这 100 年共有几天?

    2. 执行这串指令:『 bash -c "ls /check &> /dev/null && exit 10 || exit 20" 』, 回传值应该是多少?

    3. 设计一个指令,命令名称为 mykver,当执行后,屏幕会输出类似' My hostname is 'localhost' and kernel version is '4.xxx' ' 这样的字样。

  2. 纪录执行文件的指纹资料,请使用 md5sum 将 /usr/bin, /usr/sbin 里面的文件,列出文件名并排序后,以 md5sum 分析其指纹码。 分析完毕后,将数据放至于 /root/rawdata.md5 中。

  3. 进行文件的分区 :

    1. 前往 /dev/shm/check 目录,在该目录下,以 dd 这个指令,建立一个 200M 的巨型档案,文件名为 bigfile。

    2. 将该档案以 20M 为单位,进行切割,文件名为 sfile?? 这样,那个 ?? 为自行建立的分割文件名。

    3. 透过 cat 的功能,将 sfile?? 再次组合成为巨型档案,文件名为bigfile2

    4. 透过 cmp 的功能,比较 bigfile 与 bigfile2 是否为相同的档案?

  • 作业 (不提供学生答案,仅提供教师参考答案)

作业硬盘操作帮助:

  • 开启云端虚拟机前,请务必确认你开启的硬盘是'unit08',否则就会做错题目

  • 若要使用图形界面,请务必使用 student 身份登入,若需要切换身份,再启用终端机处理。

  • 若有简答题需要使用中文,请自行以第一堂课的动作自行处理输入法安装。

  • 每部虚拟机均有独特的网卡地址,请勿使用他人硬盘上传,否则计分为 0 分。

  • 每位同学均有自己的 IP 尾数,请先向老师询问您的 IP 尾数,才可以进行作业上传。

  • 最终上传作业结果,请务必使用 root 身份上传。

  • 进入操作硬盘后,先用 root 身份执行 vbird_book_setup_ip, 执行流程请参考:vbird_book_setup_ip

作业当中,某些部份可能为简答题~若为简答题时,请将答案写入 /home/student/ans.txt 当中,并写好正确题号,方便老师订正答案。 请注意,文件名写错将无法上传!


请使用 root 的身份进行如下实做的任务。 直接在系统上面操作,操作成功即可,上传结果的程序会主动找到你的实做结果。

  1. (30%)请登录这次的操作系统环境,并且依据在线的环境实做底下的题目之后,将题目的要求(指令或者是结果) 写入到 /root/ans08.txt 文件内:

    1. 当执行完成 mysha.sh 这个命令之后,该指令的回传值为多少,请写下 (1)用什么指令显示回传值? (2)回传值是多少?

    2. 在不通过 bc 这个指令的情况下,如何以 bash 的功能,计算一年有几秒? 亦即如何计算出 60*60*24*365 的结果? (1)写下指令, (2)写出结果

    3. 使用 find / 找出全系统的文件名,然后将所有数据 (包括正确与错误) 全部写入 /root/find_filename.txt, 请写下达成此目标的完整指令串。

    4. 写下一段命令(主要以echo来达成的),执行该段指令会输出' My $HOSTNAME is 'XXX' ',其中 XXX 为使用 hostname 这个指令所输出的主机名称。 例如主机名称为 station1 时,该串指令会输出' My $HOSTNAME is 'station1''。 该串命令在任何主机均可执行,但都会输出不同的消息(因为主机名不一样所致)

    5. 管理员 (root) 执行 mv 时,由于默认 alias 的关系,都会主动的加上 mv -i 此选项。 假设有个来源文件名 orifile 以及目标目录名称 desdir , 如果想要将 orifile 移动到 desdir 去的时候,请写下两个方法,让 root 执行 mv 时,不会有 -i 的默认选项 (不能 unalias 的情况下)

    6. 透过『 ll /usr/sbin/* /usr/bin/* 』搭配 cut 与 sort, uniq 等指令来设计一个指令串,执行该指令串之后会输出如下的画面, 请写下该指令串:(底下画面为示意图,实际输出的个数可能会有些许差异)

            1 r-s--x---
            1 rw-r--r--
           10 rwsr-xr-x
            3 rws--x--x
            3 rwx------
            4 rwxr-sr-x
          241 rwxrwxrwx
            8 rwxr-x---
         1633 rwxr-xr-x
      ...
  2. (10%)制作一个名为 mycmdperm.sh 的脚本指令,放置于 /usr/local/bin 里面。 该脚本的重点是这样的:

    1. 执行脚本的方式为' mycmdperm.sh command ',其中 command 为你想要取得的指令的名称

    2. 在 mycmdperm.sh 里面,指定一个变量为 cmd,这个变量的内容为 ${1},其中 ${1} 就是该脚本后面携带的第一个参数

    3. 使用' ll $( which ${cmd} ) '来取得这个 cmd 的实际权限。

    4. 让 mycmdperm.sh 具有可执行权。

    5. 最终请执行一次该指令,例如使用' mycmdperm.sh passwd '应该会秀出 passwd 的相关权限。 不过该指令应该会执行失败, 因为上述的 (c) 指令怪怪的,似乎是'命令别名无法用在脚本内'的样子。 因此,请将这个脚本的内容修订成为没有问题的形式。 (就是将命令别名改成实际的指令操作)

  3. (15%)制作一个名为 myfileperm.sh 的脚本指令,放置于 /usr/local/bin 里面。 该脚本的重点是这样的:

    1. 执行脚本的方式为' myfileperm.sh filename ',其中 filename 为你想要获得的文件名( 绝对路径或相对路径)

    2. 在 myfileperm.sh 里面,指定一个变量为 filename ,这个变量的内容为 ${1},其中 ${1} 就是该脚本后面携带的第一个参数

    3. 判断 filename 是否不存在,若不存在则回报『filename is non exist』

    4. 判断 filename 存在,且为一般档案,若是则回报『 filename is a reguler file 』

    5. 判断 filename 存在,且为一般目录,若是则回应『 filename is a directory』

  4. (15%)制作一个 mymsg.sh 的脚本指令,放置于 /usr/local/bin 底下:

    1. 当执行 mymsg.sh 时,屏幕会输出底下的字样,然后结束指令。

      [student@localhost ~]$ mymsg.shHollo!!
      My name is 'Internet Lover'...
      My server's kernel version is $kver
      I'm a student
      bye bye!!
    2. 上面的输出不能使用echo,请使用 cat 搭配 << eof 这样的指令语法来处理数据输出的信息。

  5. (10%)文件和文件内容处理方法 :

    1. 找出 /etc/services 这个档案内含有 http 的关键字那几行,且 http 只会出现在行首! 并将该数据转存成 /root/myhttpd.txt 文件

    2. 找出 examuser 这个帐号在系统所拥有的档案,并将这些文件'移动'到 /root/examuser 目录中

  6. (10%)root 的 bash 环境操作设定: (主要是修改 .bashrc 喔! 且若指令内的指令需要用到 $ 时,得输入 \$ 才可以)

    1. 做一个命令别名为 myip 的指令,这个指令会通过 ifconfig 的功能,显示出 ens3 这张网卡的 IP (只要 IP 就好喔! )。 例如 IP 为 192.168.251.12 时,则输入 myip 这个指令,屏幕只会输出 192.168.251.12 的意思。

    2. 建立一个命令别名 myerr 这个指令,这个指令会将『 echo "I am error message" 』这个讯息传输到 standard error output 去! 亦即当执行' (myerr) '时,会在屏幕上出现 I am error message,但是执行' (myerr) 2> /dev/null '时,屏幕不会有任何讯息的输出。

  7. (10%)建立一个名为 /root/split 的目录,进行如下的行为:

    1. 将 /etc/services 复制到本目录下

    2. 假设 services 容量太大了,现在请以 100K 为单位,将该文件拆解成 file_aa, file_ab, file_ac.. 文件名文件, 每个文件最大为 100K (请自行 man split 去处理)

作业结果传输:请以 root 的身份执行 vbird_book_check_unit 指令上传操作结果。 正常执行完毕的结果应会出现【XXXXXX_aa:bb:cc:dd:ee:ff_unitNN】字样。 若需要查阅自己上传资料的时间, 请在操作系统上面使用浏览器查询: http://192.168.251.254 检查相对应的课程档案。 相关流程请参考: vbird_book_check_unit


©著作权归作者所有:来自ZhiKuGroup博客作者没文化的原创作品,如需转载,请注明出处,否则将追究法律责任 来源:ZhiKuGroup博客,欢迎分享。

评论专区
  • 昵 称必填
  • 邮 箱选填
  • 网 址选填
◎已有 0 人评论
搜索
作者介绍
30天热门
×
×
本站会员尊享VIP特权,现在就加入我们吧!登录注册×
»
会员登录
新用户注册
×
会员注册
已有账号登录
×