Linux 基礎學習訓練教材 - RockyLinux 9.x

課程/課後例題參考解答

單純提供一個相對的解答,並不是標準答案!

最近更新時間: 2023/05/01

單純就是個解答的參考,寫完之後再來這邊查查看答案跟你想的一樣不一樣!?

第 08 堂課 (2023/05/01)

  • 例題 8.1.1-1:
    1. var=${變數}
    2. var=$(指令)
    3. var=$(( 加減乘除計算式 ))
    4. var="變數值,但保有 $ 功能"
    5. var='變數值,純文字'
    6. var=`指令`
  • 例題 8.1.1-2:
    # A. 先用 which 功能
    [root@station10-101 ~]# which ifconfig chfn
    /usr/sbin/ifconfig
    /usr/bin/chfn
    
    # B. 再用 $() 的子程式功能
    [root@station10-101 ~]# ll $(which ifconfig chfn)
    -rws--x--x. 1 root root 32032 Nov 17 05:55 /usr/bin/chfn
    -rwxr-xr-x. 1 root root 81384 May 16  2022 /usr/sbin/ifconfig
    
    透過這個子程式的功能,我們就不用手動輸入剛剛 which 搜尋到的檔名資料了!
  • 例題 8.1.1-3:
    1. 先討論『沒有權限的檔案執行』會產生什麼後果:
      [root@station10-101 ~]# /etc/passwd
      -bash: /etc/passwd: Permission denied
      [root@station10-101 ~]# echo $?
      126
      # 意思是說,沒有權限執行時,回傳值應該會是 126 的意思!
      
    2. 再來討論『找不到執行檔』的時候,回傳的訊息又是什麼?
      [root@station10-101 ~]# vbirdcommand
      bash: vbirdcommand: command not found...
      [root@station10-101 ~]# echo $?
      127
      # 所以,這種情況會回傳 127 的數值
      
    3. 接下來,討論一下 bash 針對這些回傳值 (exit status) 的定義:
      [root@station10-101 ~]# man bash
      ......
      EXIT STATUS
             The  exit status of an executed command is the value returned by the waitpid
             system call or equivalent function.  Exit statuses fall between 0  and  255,
             though,  as  explained  below, the shell may use values above 125 specially.
             Exit statuses from shell builtins and compound commands are also limited  to
             this  range.  Under certain circumstances, the shell will use special values
             to indicate specific failure modes.
      
             For the shell's purposes, a command which exits with a zero exit status  has
             succeeded.   An exit status of zero indicates success.  A non-zero exit sta‐
             tus indicates failure.  When a command terminates on a fatal signal N,  bash
             uses the value of 128+N as the exit status.
      
             If a command is not found, the child process created to execute it returns a
             status of 127.  If a command is found but is not executable, the return sta‐
             tus is 126.
      
             If  a command fails because of an error during expansion or redirection, the
             exit status is greater than zero.
      
             Shell builtin commands return a status of 0 (true) if successful,  and  non-
             zero  (false) if an error occurs while they execute.  All builtins return an
             exit status of 2 to indicate incorrect usage, generally invalid  options  or
             missing arguments.
      
             Bash  itself  returns the exit status of the last command executed, unless a
             syntax error occurs, in which case it exits with a non-zero value.  See also
             the exit builtin command below.
      ......
      
      很簡單就得到沒權限是 126,而找不到檔案就是 127 囉!
    4. 根據上面的說法,回傳值應該要介於 0~255 之間~而 0 代表執行指令成功,非為 0 就是不成功!
    5. 要查回傳值的時候,請注意到底要查誰?查那一個指令的說明這樣!
      [root@station10-101 ~]# ls /vbird
      ls: cannot access '/vbird': No such file or directory
      [root@station10-101 ~]# echo $?
      2
      # 很明顯,應該是要查看 ls 吧!
      
      [root@station10-101 ~]# man ls
      ......
         Exit status:
             0      if OK,
      
             1      if minor problems (e.g., cannot access subdirectory),
      
             2      if serious trouble (e.g., cannot access command-line argument).
      ......
      # 結果的 2 說的是無法取得指令列所帶的參數 (args) 啊!
      
  • 例題 8.1.2-1:
    # 單純在指令的最後面加上資料流重導向:
    [student@station10-101 15:26 1 ~]$ date; uptime; uname -r > myfile.txt
    Sun Apr 30 03:17:55 PM CST 2023
     15:17:55 up 8 min,  2 users,  load average: 0.00, 0.04, 0.03
    [student@station10-101 15:26 2 ~]$ cat myfile.txt
    5.14.0-162.12.1.el9_1.0.2.x86_64
    # 很明顯的發現,上述指令分為三大部份
    # 1. date
    # 2. uptime
    # 3. uname -r > myfile.txt
    # 所以 myfile.txt 只會保留 uname -r 的結果!
    
    # 將連續輸入的資料用大括號保留下來:
    [student@station10-101 15:26 3 ~]$ (date; uptime; uname -r ) > myfile.txt
    [student@station10-101 15:28 4 ~]$ cat myfile.txt
    Sun Apr 30 03:18:29 PM CST 2023
     15:18:29 up 8 min,  2 users,  load average: 0.00, 0.03, 0.03
    5.14.0-162.12.1.el9_1.0.2.x86_64
    
    大括號將連續資料包起來後,所有的輸出資料最終會彙整在一起後,再傳給 > 進行後續的動作!
  • 例題 8.1.2-2:
    # 先測試存在檔案時的狀態:
    [student@station10-101 16:35 16 ~]$ ls -d /etc &> /dev/null || echo no-exist && echo exist
    exist
    
    # 再測試不存在檔案時的狀態:
    [student@station10-101 16:35 16 ~]$ ls -d /vbird &> /dev/null || echo no-exist && echo exist
    no-exist
    exist
    
    我們可以很輕易的發現,若檔案存在時,指令沒啥問題,但是當檔案不存在時,卻兩者會同時出現!在這裡你要先注意:
    1. 指令列的連續指令都是依序執行的
    2. 回傳值在每個指令之後都會改變,也就是 $? 結果會一直改變
    讓我們解析一下錯誤的狀態是什麼情況?
    ls -d /vbird &> /dev/null || echo no-exist && echo exist
               $?=2                $?=0             $?=0 
              執行失敗       因為失敗所以執行    因為成功所以執行
    
    所以,基本上, && 一定要放在 || 之前,否則邏輯上會出現問題喔!
  • 例題 8.1.3-1:
    # A. 使用連續指令下達的方式來處理這個任務即可:
    [student@station10-101 20:27 1 ~]$ test -e /etc; echo $?
    0
    # 答案為正確,因此是存在這個檔名的
    
    # B. 判斷 SUID 使用 -S 來測試
    [student@station10-101 20:28 3 ~]$ test -u /usr/bin/passwd ; echo $?
    0
    # 答案為正確,因此該檔案具有 SUID 的旗標
    
    # C. 判斷主機名稱是否為我自己設定的樣子?
    [student@station10-101 20:28 4 ~]$ test "mylocalhost" == ${HOSTNAME} ; echo $?
    1
    # 答案為不正確,所以不是 mylocalhost 的樣式!讓我們來檢查一下:
    [student@station10-101 20:30 5 ~]$ echo ${HOSTNAME}
    station10-101.gocloud.vm
    # 果然不是!
    
    # D. 重新修改小指令:
    [root@station10-101 ~]# vim /usr/local/bin/checkfile
    #!/bin/bash
    #ls -d ${1} &> /dev/null && echo "${1} exist" || echo "${1} non-exist"
    test -e ${1} && echo "${1} exist" || echo "${1} non-exist"
    
    [root@station10-101 ~]# checkfile /etc
    /etc exist
    
    最後一題可以修改一下原本使用 ls 判斷檔案是否存在的方式,使用 test 會更直覺!!
  • 例題 8.1.3-2:
    這一題相對簡單,所以就直接輸入指令來看看即可:
    [student@station10-101 21:24 1 ~]$ [ -e /etc ]; echo $?
    0
    
    [student@station10-101 21:24 2 ~]$ [ -u /usr/bin/passwd ]; echo $?
    0
    
    [student@station10-101 21:25 3 ~]$ [ "${HOSTNAME}" == "mylocalhost" ] ; echo $?
    1
    
  • 例題 8.1.4-1:
    1. 當目標目錄不存在時,第一次複製不需要詢問是否覆蓋的情境:
      [root@station10-101 ~]# cd /dev/shm
      [root@station10-101 shm]# cp -a /etc .
      [root@station10-101 shm]# ll
      總計 0
      drwxr-xr-x. 135 root root 5280  4月 19 14:34 etc
      
      簡單的複製成功了!
    2. 第二次重複複製,就會發現出現是否覆蓋的問題!你可以按 y 也可以 [ctrl]-c 中斷
      [root@station10-101 shm]# cp -a /etc .
      cp: overwrite './etc/lvm/lvm.conf'? y
      cp: overwrite './etc/lvm/lvmlocal.conf'? y
      cp: overwrite './etc/lvm/profile/cache-mq.profile'? y
      cp: overwrite './etc/lvm/profile/cache-smq.profile'? ^C
      
    3. 絕對路徑與相對路徑方式,都可以執行指令。另外,透過反斜線,可以略過命令別名的設定!
      [root@station10-101 shm]# /bin/cp -a /etc .   <==這個是絕對路徑
      [root@station10-101 shm]# \cp -a /etc .       <==這個是略過命令別名
      
  • 例題 8.1.4-2:
    其實就是將題目中的指令,在 .bashrc 裡面加上命令別名即可!
    [student@station10-101 21:46 1 ~]$ vim .bashrc
    alias cp="cp -i"
    alias rm="rm -i"
    alias mv="mv -i"
    
  • 例題 8.1.5-1:
    # A. 建立命令別名
    [student@station10-101 21:48 3 ~]$ alias geterr=' echo "I am error" 1>&2 '
    # 這個別名的意義是,執行 echo 後,將資料丟到錯誤訊息上面去!
    
    # B. 直接執行看看
    [student@station10-101 21:49 4 ~]$ geterr
    I am error
    # 確實有訊息輸出啊!
    
    # C. 將錯誤資料丟棄
    [student@station10-101 21:49 6 ~]$ geterr 2> /dev/null
    I am error
    # 咦!怎麼還是出現訊息?應該錯誤訊息會被丟棄才對!
    
    # D. 將訊息整個包起來看看:
    [student@station10-101 21:50 7 ~]$ (geterr) 2> /dev/null
    # 這次確實沒資料了!
    
    alias 命令別名畢竟是轉傳資料過一次,因此大概是執行完畢之後,才丟到外部指令來。所以,訊息已經輸出了, 最後那個 2> /dev/null 就會沒有訊息丟棄~使用小括號將訊息全部整合,那就可以將錯誤訊息最後切給 2> 了!
  • 例題 8.2.1-1:
    # A. 找尋檔名
    [student@station10-101 22:04 9 ~]$ man find
           -name pattern
                  Base  of  file  name  (the path with the leading directories removed) matches
                  shell pattern pattern.  Because the leading directories are removed, the file
                  names considered for a match with -name will never include a slash, so `-name
                  a/b' will never match anything (you probably need to use -path  instead).   A
                  warning  is  issued  if  you  try to do this, unless the environment variable
                  POSIXLY_CORRECT is set.  The metacharacters (`*', `?', and `[]') match a  `.'
                  at  the start of the base name (this is a change in findutils-4.2.2; see sec‐
                  tion STANDARDS CONFORMANCE below).  To ignore a directory and the files under
                  it,  use  -prune; see an example in the description of -path.  Braces are not
                  recognised as being special, despite the fact that some shells including Bash
                  imbue braces with a special meaning in shell patterns.  The filename matching
                  is performed with the use of the fnmatch(3) library function.   Don't  forget
                  to enclose the pattern in quotes in order to protect it from expansion by the
                  shell.
    
    [student@station10-101 21:53 8 ~]$ find /etc -name '*passwd*'
    find: ‘/etc/lvm/archive’: 拒絕不符權限的操作
    find: ‘/etc/lvm/backup’: 拒絕不符權限的操作
    find: ‘/etc/lvm/cache’: 拒絕不符權限的操作
    /etc/pam.d/passwd
    find: ‘/etc/pki/rsyslog’: 拒絕不符權限的操作
    find: ‘/etc/sssd’: 拒絕不符權限的操作
    find: ‘/etc/sos/cleaner’: 拒絕不符權限的操作
    /etc/passwd-
    find: ‘/etc/grub.d’: 拒絕不符權限的操作
    find: ‘/etc/polkit-1/rules.d’: 拒絕不符權限的操作
    find: ‘/etc/polkit-1/localauthority’: 拒絕不符權限的操作
    /etc/passwd
    ....
    
    # B. 因為錯誤訊息不重要,所以,將它丟棄吧!
    [student@station10-101 22:07 11 ~]$ find /etc -name '*passwd*' 2> /dev/null
    /etc/pam.d/passwd
    /etc/passwd-
    /etc/passwd
    /etc/security/opasswd
    
    # C. 轉存正確訊息
    [student@station10-101 22:07 12 ~]$ find /etc -name '*passwd*' 2> /dev/null > ~student/find_passwd.txt
    [student@station10-101 22:08 13 ~]$ cat ~student/find_passwd.txt
    /etc/pam.d/passwd
    /etc/passwd-
    /etc/passwd
    /etc/security/opasswd
    
    # D. 開始進行訊息的累加!
    [student@station10-101 22:10 15 ~]$ find /etc -name "*shadow*" 2> /dev/null
    /etc/gshadow
    /etc/gshadow-
    /etc/pam.d/sssd-shadowutils
    /etc/shadow-
    /etc/shadow
    [student@station10-101 22:10 16 ~]$ find /etc -name "*shadow*" 2> /dev/null >> ~student/find_passwd.txt
    
    # E. 最終看看檔案內容
    [student@station10-101 22:10 17 ~]$ cat ~student/find_passwd.txt
    /etc/pam.d/passwd
    /etc/passwd-
    /etc/passwd
    /etc/security/opasswd
    /etc/pam.d/sssd-shadowutils
    /etc/shadow-
    /etc/gshadow
    /etc/shadow
    /etc/gshadow-
    
  • 例題 8.2.1-2:
    # A.B. 測試 cat 的用法
    [student@station10-101 22:11 18 ~]$ cat
    I am VBird
    I am VBird
    HaHaHa
    HaHaHa
    [ctrl]+d
    
    # C. 測試輸入資料轉存成為檔案,無須使用 vim 喔!
    [student@station10-101 22:30 19 ~]$ cat > mycat.txt
    I am vbird
    HaHaHa
    [student@station10-101 22:32 20 ~]$ cat mycat.txt
    I am vbird
    HaHaHa
    
    # D. 讀入檔案
    [student@station10-101 22:32 21 ~]$ cat < /etc/hosts
    127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
    ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
    
    # E. 讀入後轉存
    [student@station10-101 22:33 22 ~]$ cat < /etc/hosts  >> mycat.txt
    [student@station10-101 22:34 23 ~]$ cat mycat.txt
    I am vbird
    HaHaHa
    127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
    ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
    
  • 例題 8.2.2-1:
      # A.B. 先用簡單的方法來處理檔名的搜尋
      [student@station10-101 22:39 27 ~]$ find /etc -name '*.conf' 2> /dev/null
      /etc/lvm/lvm.conf
      /etc/lvm/lvmlocal.conf
      /etc/resolv.conf
      /etc/dnf/dnf.conf
      /etc/dnf/plugins/kpatch.conf
      
      [student@station10-101 22:41 31 ~]$ find /etc 2> /dev/null | grep '\.conf$'
      # 關鍵字的部份會多出顏色的顯示!比較好!
      
      # C. 計算檔案數量
      [student@station10-101 22:41 31 ~]$ find /etc 2> /dev/null | grep '\.conf$' | wc
          327     327   10415
      [student@station10-101 22:43 32 ~]$ find /etc 2> /dev/null | grep '\.conf$' | wc -l
      327
      
  • 例題 8.2.2-2:
    # A. 使用 cut 來切割具有固定分隔字元的資料即可
    [student@station10-101 22:44 34 ~]$ cut -d ':' -f 1,7 /etc/passwd
    root:/bin/bash
    bin:/sbin/nologin
    daemon:/sbin/nologin
    adm:/sbin/nologin
    lp:/sbin/nologin
    ......
    
    # B. 因為 shell 名稱很多,因此需要進行排序,排序完畢再以 uniq 去計算次數即可
    [student@station10-101 22:47 35 ~]$ cut -d ':' -f 7 /etc/passwd
    [student@station10-101 22:48 36 ~]$ cut -d ':' -f 7 /etc/passwd | sort
    [student@station10-101 22:48 37 ~]$ cut -d ':' -f 7 /etc/passwd | sort | uniq -c
          8 /bin/bash
          1 /bin/sync
          1 /sbin/halt
         31 /sbin/nologin
          1 /sbin/shutdown
          2 /usr/sbin/nologin
    
    # C. 用 last 分析登入者,然後分析登入次數
    [student@station10-101 22:48 40 ~]$ last
    [student@station10-101 22:50 41 ~]$ last | awk '{print $1}'
    [student@station10-101 22:50 42 ~]$ last | awk '{print $1}' | sort
    [student@station10-101 22:51 43 ~]$ last | awk '{print $1}' | sort | uniq -c
          1
          1 myuser2
         23 reboot
         23 root
         13 student
          1 wtmp
    
    # D. 只想取出 IPv4 的 IP 資料
    [student@station10-101 22:51 44 ~]$ ip addr show
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
        inet 127.0.0.1/8 scope host lo
           valid_lft forever preferred_lft forever
        inet6 ::1/128 scope host
           valid_lft forever preferred_lft forever
    2: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
        link/ether 52:54:00:ba:0b:fc brd ff:ff:ff:ff:ff:ff
        altname enp0s3
        inet 172.16.2.253/16 brd 172.16.255.255 scope global dynamic noprefixroute ens3
           valid_lft 256870sec preferred_lft 256870sec
        inet6 fe80::5054:ff:feba:bfc/64 scope link noprefixroute
           valid_lft forever preferred_lft forever
    
    [student@station10-101 22:52 45 ~]$ ip addr show | grep 'inet '
        inet 127.0.0.1/8 scope host lo
        inet 172.16.2.253/16 brd 172.16.255.255 scope global dynamic noprefixroute ens3
    
    # E. 只想要 IP 位址,因為在第二欄位,所以使用 awk 剛剛好!
    [student@station10-101 22:54 46 ~]$ ip addr show | grep 'inet ' | awk '{print $2}'
    127.0.0.1/8
    172.16.2.253/16
    
    # F. 要將資料從螢幕輸出,同時輸出到檔案,就得要使用 tee 了!
    [student@station10-101 22:55 47 ~]$ ip addr show | grep 'inet ' | awk '{print $2}' | tee /dev/shm/myip.txt
    127.0.0.1/8
    172.16.2.253/16
    
    [student@station10-101 22:56 48 ~]$ cat /dev/shm/myip.txt
    127.0.0.1/8
    172.16.2.253/16
    
  • 例題 8.3 課後練習
    1. 簡單的指令操作行為:
      # a. 計算日數
      [root@station10-101 shm]# echo $(( 100*365 ))
      36500
      [root@station10-101 shm]# echo $(( 25*366 + 75*365 ))
      36525
      
      # b. 推算回傳值
      [root@station10-101 shm]# bash -c "ls /check &> /dev/null && exit 10 || exit 20"
      [root@station10-101 shm]# echo $?
      20
      
      # c. 命令別名
      [root@station10-101 shm]# alias mykver='echo "My hostname is \"${HOSTNAME}\" and kernel version is $(uname -r)"'
      [root@station10-101 shm]# mykver
      My hostname is "station2-253.gocloud.vm" and kernel version is 5.14.0-162.12.1.el9_1.0.2.x86_64
      
    2. 指紋資料的紀錄
      [root@station10-101 ~]# find /usr/sbin /usr/bin -type f 
      [root@station10-101 ~]# find /usr/sbin /usr/bin -type f | sort 
      [root@station10-101 ~]# md5sum $( find /usr/sbin /usr/bin -type f | sort ) 
      b97fa724729af2bd70948884e7738392  /usr/bin/[
      85db5abdba8c1992921de8bbe4222f7d  /usr/bin/ac
      d495cf8be0fc8246a287209ec91d53a5  /usr/bin/aconnect
      24f7909265325adcfb906b130beedc60  /usr/bin/addr2line
      af1ce0b39c3ce9cbfaa63e1d7bf95e30  /usr/bin/airscan-discover
      ......
      [root@station10-101 ~]# md5sum $( find /usr/sbin /usr/bin -type f | sort ) > /root/rawdata.md5
      
    3. 進行檔案的分割動作
      # a. 建立巨型檔案
      [student@station10-101 ~]$ mkdir /dev/shm/check
      [student@station10-101 ~]$ cd /dev/shm/check/
      [student@station10-101 check]$ dd if=/dev/zero of=bigfile bs=200M count=1
      記錄了 1+0 的讀入
      記錄了 1+0 的寫出
      209715200位元組(210 MB,200 MiB)已複製,0.217285 s,965 MB/s
      [root@station10-101 check]# ll
      總用量 204800
      -rw-r--r--. 1 student student 209715200  4月 30 15:59 bigfile
      
      # b. 進行分割喔!
      [root@station10-101 check]# man split
      SYNOPSIS
             split [OPTION]... [FILE [PREFIX]]
      ......
             -b, --bytes=SIZE
                    put SIZE bytes per output file
      
      [student@station10-101 check]$ split -b $(( 20*1024*1024 )) bigfile sfile
      [student@station10-101 check]$ ll
      總用量 409600
      -rw-r--r--. 1 student student 209715200  4月 30 15:59 bigfile
      -rw-r--r--. 1 student student  20971520  4月 30 16:00 sfileaa
      -rw-r--r--. 1 student student  20971520  4月 30 16:00 sfileab
      -rw-r--r--. 1 student student  20971520  4月 30 16:00 sfileac
      -rw-r--r--. 1 student student  20971520  4月 30 16:00 sfilead
      -rw-r--r--. 1 student student  20971520  4月 30 16:00 sfileae
      -rw-r--r--. 1 student student  20971520  4月 30 16:00 sfileaf
      -rw-r--r--. 1 student student  20971520  4月 30 16:00 sfileag
      -rw-r--r--. 1 student student  20971520  4月 30 16:00 sfileah
      -rw-r--r--. 1 student student  20971520  4月 30 16:00 sfileai
      -rw-r--r--. 1 student student  20971520  4月 30 16:00 sfileaj
      
      # c. 將檔案組合起來吧!
      [student@station10-101 check]$ cat sfile* > bigfile2
      [student@station10-101 check]$ ll bigfile*
      -rw-r--r--. 1 student student 209715200  4月 30 15:59 bigfile
      -rw-r--r--. 1 student student 209715200  4月 30 16:01 bigfile2
      
      # d. 確認兩個檔案的內容是一模一樣的!
      [student@station10-101 check]$ cmp bigfile bigfile2
      [student@station10-101 check]$ diff bigfile bigfile2
      # 沒出現任何訊息,就代表兩個檔案內容完全一致!
      
      [student@station10-101 check]$ md5sum bigfile*
      3566de3a97906edb98d004d6b947ae9b  bigfile
      3566de3a97906edb98d004d6b947ae9b  bigfile2
      # 指紋碼相同,也代表這兩個檔案內容一致啊!
      
修改歷史:
  • 2023/02/17:RHEL 改版到 EL9 了,只好再度改版!否則教學上面挺困擾!
2023/02/17 以來統計人數
計數器
其他連結
環境工程模式篇
鳥園討論區
鳥哥舊站

今日 人數統計
昨日 人數統計
本月 人數統計
上月 人數統計