Linux 基础学习训练教材 - CentOS 7.x

第 8 堂课:bash 指令连续下达与数据流重导向

文本界面下指令的连续下达方式、数据流重新导向以及大量的应用题型!

最近更新时间: 2017/03/26

前一节课针对 bash 做简单的变量与环境操作之介绍,本节将针对 bash 环境中常用的连续指令下达方式, 以及数据处理常用的数据流重导向与管线命令进行介绍。这些数据处理的技术对于管理员来说是相当重要的, 尤其在自撰脚本程序分析注册表时,这就显的非常的重要。

8.1:连续指令的下达

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

8.1.1:指令回传值

指令、变量、计算式可以使用特殊的符号来处理,请完成底下的练习:

例题:请将『变量』、『指令』、『数学计算式』、『纯文本』、『保持 $ 功能』等写入下方的空格中
  1. var=${     }
  2. var=$(     )
  3. var=$((     ))
  4. var="     "
  5. var='     '
  6. var=`     `
例题:请找出 ifconfig 与 chfn 等指令后,列出该指令的权限
  1. 先以 which command 的方式找出指令的全名
  2. 将上述的结果,使用 ls -l 显示出来。请搭配前一个例题的符号 ($, ', ", ` 等) 来处理。

指令的运行正确与否与后续的处理有关。Linux 环境下缺省的指令正常结束回传值为 0 ,调用的方式为使用『 echo $? 』即可, 亦即找出 ? 这个变量的内容即可。

例题:了解各指令回传值的意义
  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
五  7月 29 22:16:04 CST 2016
 22:16:04 up 14 days, 23:35,  2 users,  load average: 0.00, 0.01, 0.05
3.10.0-327.el7.x86_64

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

[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 来动作,不过我们假设该目录的检查为使用 ls 检测即可。 当 ls /dev/shm/check 显示错误时,表示该文件名不存在,此时才使用 mkdir (不要加上 -p 的选项) 来处理。
[student@localhost ~]$ ls -d /dev/shm/check || mkdir /dev/shm/check
ls: 无法访问 /dev/shm/check: 没有此一文件或目录
[student@localhost ~]$ ls -d /dev/shm/check || mkdir /dev/shm/check
/dev/shm/check
[student@localhost ~]$ ls -d /dev/shm/check ; mkdir /dev/shm/check
/dev/shm/check
mkdir: 无法创建目录‘/dev/shm/check’: 文件已存在
第一次运行时,由于尚未有该目录,所以显示找不到,但是第二次运行时,就会有该目录,因此 mkdir 的动作就没有进行。 若将中间分隔改为分号 (;) 时,就会产生重复 mkdir 的问题了。因此,比较好的运行方式,还是需要使用 || 较佳!
例题:当 /dev/shm/check 存在时,就将该目录删除,否则就不进行任何动作
[student@localhost ~]$ ls -d /dev/shm/check && rmdir /dev/shm/check
/dev/shm/check
[student@localhost ~]$ ls -d /dev/shm/check && rmdir /dev/shm/check
ls: 无法访问 /dev/shm/check: 没有此一文件或目录
与前一个例题相似,通过 ls 简易的进行搜索的任务,读者也同样会发现两次运行的结果并不相同。

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

[student@localhost ~]$ ls -d /etc && echo exist || echo non-exist
/etc
exist
[student@localhost ~]$ ls -d /vbird && echo exist || echo non-exist
ls: 无法访问 /vbird: 没有此一文件或目录
non-exist

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

[student@localhost ~]$ ls -d /etc &> /dev/null && echo exist || echo non-exist
exist
[student@localhost ~]$ ls -d /vbird &> /dev/null && echo exist || echo non-exist
non-exist
例题:
上述的指令能否写成:『 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 exist || echo non-exist

[root@localhost ~]# chmod a+x /usr/local/bin/checkfile
[root@localhost ~]# checkfile /etc
exist
[root@localhost ~]# checkfile /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 -r file -o -x file,则 file 具有 r 或 x 权限时,就可回传 true。
!反相状态,如 test ! -x file ,当 file 不具有 x 时,回传 true

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

例题:
  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 exist || echo non-exist

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

[  "$HOME"  ==  "$MAIL"  ]
[□"$HOME"□==□"$MAIL"□]
 ↑       ↑  ↑       ↑
例题:
  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
[student@localhost ~]$ echo $?

上述的 ${@} 代表指令后面接的任何参数,因此你可以运行 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 exist || echo non-exist
ll -d ${1} && echo exist || echo non-exist

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

[root@localhost ~]# alias
alias 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 which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'

[student@localhost ~]$ alias
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 vi='vim'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'

因此读者应该能知道为何 /bin/ls -d /etc 与 ls -d /etc 输出的结果会有颜色差异的问题了。此外,管理员运行 mv, cp, rm 等管理文件的指令时, 为了避免不小心导致的文件覆盖等问题,于是仅有 root 的身份会加上 -i 的选项,提示管理员相关的文件覆盖问题。

例题:
  1. 使用 root 的身份切换路径到 /dev/shm 底下
  2. 将 /etc 整个目录拷贝到 『本目录』 底下
  3. 若将上述指令重新运行一次,会发生什么问题?
  4. 若你确定文件名就是需要覆盖,那可以使用什么方式来处理 (思考 A. 使用绝对路径不要用命令别名 B. 让指令自动忽略命令别名)
例题:
  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
例题:
  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 等指令。因此,将指令对于数据的加载与输出汇整如下图:

图8.2.1、指令运行过程的数据传输情况
图8.2.1、指令运行过程的数据传输情况
  • standard output 与 standard error output

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

  1. 标准输入  (stdin) :代码为 0 ,使用 < 或 << ;
  2. 标准输出  (stdout):代码为 1 ,使用 > 或 >> ;
  3. 标准错误输出(stderr):代码为 2 ,使用 2> 或 2>> ;
例题:
  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 这个指令就是直接让你敲击键盘来由屏幕输出信息。

例题:
  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, |) 的功能。管线的意思是, 将前一个指令的标准输出作为下一个指令的标准输入来处理!流程有点像底下这样的图标:

图8.2.2、管线命令处理示意图
图8.2.2、管线命令处理示意图

另外,这个管线命令『 | 』仅能处理经由前面一个指令传来的正确信息,也就是 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 :将数据依据行数或容量数切割成数份
例题:我想要查看 /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 』
例题:
  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:课后练习操作

前置动作:请使用 unit08 的硬盘进入作业环境,并请先以 root 身分运行 vbird_book_setup_ip 指令设置好你的学号与 IP 之后,再开始底下的作业练习。

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

  1. 尝试以系统上面的实做数据后,回答下列问题,并将答案写入 /root/ans08.txt 当中:
    1. 当运行完成 mysha.sh 这个指令之后,该指令的回传值为多少?
    2. 在不通过 bc 这个指令的情况下,如何以 bash 的功能,计算一年有几秒?亦即如何计算出 60*60*24*365 的结果?
    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 这个选项。请写下两个方法, 让 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. 制作一个名为 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. 制作一个名为 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. 制作一个 mymsg.sh 的脚本指令,放置于 /usr/local/bin 底下:
    1. 主要使用 cat 搭配 << eof 这样的指令语法来处理
    2. 当运行 mymsg.sh 时,屏幕会输出底下的字样,然后结束指令。
      [student@localhost ~]$ mymsg.sh
      Hollo!!
      My name is 'Internet Lover'...
      My server's kernel version is $kver
      I'm a student
      bye bye!!
      
  5. 文件与文件内容处理方法:
    1. 找出 /etc/services 这个文件内含有 http 的关键字那几行,并将该数据转存成 /root/myhttpd.txt 文件
    2. 找出 examuser 这个帐号在系统所拥有的文件,并将这些文件放置到 /root/examuser 目录中
  6. root 的 bash 环境操作设置: (主要是修改 .bashrc 喔!且指令内的指令需要用到 $ 时,得输入 \$ 才可以)
    1. 做一个命令别名为 myip 的指令,这个指令会通过 ifconfig 的功能,显示出 eth0 这张网卡的 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. 创建一个名为 /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.250 检查相对应的课程文件。

修改历史:
  • 2016/11/17:这个学期也太疲累,一直找不出时间来重新处理这篇写到一半的东西~四个月后终于有时间可以完成一下~
  • 2017/03/26:加入了作业了!这一章的作业很多其实不需要实际的作业环境就可以先练习啰!
2016/11/17以来统计人数
计数器
其他链接
环境工程模式篇
鸟园讨论区
鸟哥旧站

今日 人数统计
昨日 人数统计
本月 人数统计
上月 人数统计