【DB筆試面試275】 與SHELL腳本相關的一些筆試面試題(目前37道,後續持續更新)
- 2019 年 10 月 10 日
- 筆記
本小節以幾道真題為例,簡單講解與SHELL有關的面試題。在實際工作中,要寫的SHELL腳本要複雜得多。
真題1、SHELL腳本是什麼?它是必需的嗎?
答案:一個SHELL腳本就是一個文本文件,它包含一個或多個命令。系統管理員會經常需要使用多個命令來完成一項任務,此時可以添加這些所有命令在一個文本文件(SHELL腳本)中來完成這些日常工作任務。
真題2、什麼是默認登錄SHELL,如何改變指定用戶的登錄SHELL?
答案:在Linux作業系統中,「/bin/bash」是默認登錄SHELL,是在創建用戶時分配的。使用chsh命令可以改變默認的SHELL。示例如下所示:
# chsh <用戶名> -s <新shell> # chsh lhr -s /bin/sh
真題3、可以在SHELL腳本中使用哪些類型的變數?
答案:在SHELL腳本,可以使用兩種類型的變數:系統變數和用戶變數。
系統變數是由系統自己創建的。這些變數通常由大寫字母組成,可以通過「set」命令查看。
用戶變數由系統用戶來生成和定義,變數的值可以通過命令「echo $<變數名>」查看。
真題4、如何將標準輸出和錯誤輸出同時重定向到同一位置?
答案:有兩個方法可以來實現:
方法一,使用「2>&1」,例如:
ls /usr/share/doc > out.txt 2>&1
方法二,使用「&>」,例如:
ls /usr/share/doc &> out.txt
真題5、SHELL腳本中「if」語法如何嵌套?
答案:基礎語法如下:
if [ 條件 ] then 命令1 命令2 … else if [ 條件 ] then 命令1 命令2 … else 命令1 命令2 … fi fi
真題6、SHELL腳本中「$?」標記的用途是什麼?
答案:在寫一個SHELL腳本時,如果想要檢查前一命令是否執行成功,那麼可以使用「$?」來檢查前一條命令的結束狀態。簡單的例子如下所示:
root@localhost:~# ls /usr/bin/shar /usr/bin/shar root@localhost:~# echo $? 0
如果結束狀態是0,那麼說明前一個命令執行成功。
root@localhost:~# ls /usr/bin/shar /usr/bin/shar root@localhost:~# echo $? 0
如果結束狀態不是0,那麼說明命令執行失敗。
真題7、在SHELL腳本中如何比較兩個數字?
答案:在if-then中使用測試命令( -gt 等)來比較兩個數字,例子如下:
root@localhost:~# ls /usr/bin/shar /usr/bin/shar root@localhost:~# echo $? 0
SHELL裡面比較字元的常用寫法:
-eq 等於 -ne 不等於 -gt 大於 -lt 小於 -le 小於等於 -ge 大於等於 -z 空串 = 兩個字元相等 != 兩個字元不等 -n 非空串
真題8、SHELL腳本中break命令的作用有哪些?
答案:break命令可以退出循環,可以在while和until循環中使用break命令跳出循環。
真題9、SHELL腳本中continue命令的作用有哪些?
答案:continue命令不同於break命令,它只跳出當前循環的迭代,而不是整個循環。continue命令很多時候是很有用的,例如錯誤發生,但依然希望繼續執行外層循環的時候。
真題10、請寫出SHELL腳本中Case語句的語法。
答案:基礎語法如下:
case $arg in pattern | sample) # arg in pattern or sample ;; pattern1) # arg in pattern1 ;; *) #default ;; esac
說明:pattern1是正則表達式,可以使用下面任意字元:
① *表示任意字串
② ?表示任意字元
③ [abc]表示a,b,或c三字元其中之一
④ [a-n]表示從a到n的任一字元
⑤ |表示多重選擇
示例:
#!/bin/sh echo -n "enter a number from 1 to 4:" read ANS case $ANS in 1) echo "you select 1" ;; 2)echo "you select 2" ;; 3) echo "you select 3" ;; 4) echo "you select 4" ;; *)echo "'basename $0':This is not between 1 and 4 " >&2 exit ;; esac
測試:
[root@localhost shell]# sh case1.sh enter a number from 1 to 4:1 you select 1 [root@localhost shell]# sh case1.sh enter a number from 1 to 4:5 'basename case1.sh':This is not between 1 and 4
真題11、請寫出SHELL腳本中while循環語法?
答案:如同for循環,while循環只要條件成立就會重複執行它的命令塊。不同於for循環,while循環會不斷迭代,直到它的條件不為真。基礎語法:
while [ 條件 ] do 命令… done
真題12、如何使腳本可執行?
答案:使用chmod命令來使腳本可執行。例子如下:
# chmod a+x myscript.sh
真題13、「#!/bin/bash」的作用是什麼?
答案:「#!/bin/bash」是SHELL腳本的第一行,意思是後續命令都通過/bin/bash來執行。
真題14、請寫出SHELL腳本中for循環的語法。
答案:for循環的基礎語法:
for 變數 in 循環列表 do 命令1 命令2 …. 最後命令 done
真題15、如何調試SHELL腳本?
答案:使用「-x」參數(sh -x myscript.sh)可以調試SHELL腳本。另一個種方法是使用「-nv」參數(sh -nv myscript.sh)。
真題16、SHELL腳本如何比較字元串?
答案:test命令可以用來比較字元串。測試命令會通過比較字元串中的每一個字元來比較。其實,test還有其它用途:
1)判斷表達式
if test (表達式為真) if test !表達式為假 test 表達式1 –a 表達式2 兩個表達式都為真 test 表達式1 –o 表達式2 兩個表達式有一個為真
2)判斷字元串
test –n 字元串 字元串的長度非零 test –z 字元串 字元串的長度為零 test 字元串1=字元串2 字元串相等 test 字元串1!=字元串2 字元串不等
3)判斷整數
test 整數1 –eq 整數2 整數相等 test 整數1 –ge 整數2 整數1大於等於整數2 test 整數1 –gt 整數2 整數1大於整數2 test 整數1 –le 整數2 整數1小於等於整數2 test 整數1 –lt 整數2 整數1小於整數2 test 整數1 –ne 整數2 整數1不等於整數2
4)判斷文件
test File1 –ef File2 兩個文件具有同樣的設備號和i結點號 test File1 –nt File2 文件1比文件2 新 test File1 –ot File2 文件1比文件2 舊 test –b File 文件存在並且是塊設備文件 test –c File 文件存在並且是字元設備文件 test –d File 文件存在並且是目錄 test –e File 文件存在 test –f File 文件存在並且是正規文件 test –g File 文件存在並且是設置了組ID test –G File 文件存在並且屬於有效組ID test –h File 文件存在並且是一個符號鏈接(同-L) test –k File 文件存在並且設置了sticky位 test –L File 文件存在並且是一個符號鏈接(同-h) test –o File 文件存在並且屬於有效用戶ID test –p File 文件存在並且是一個命名管道 test –r File 文件存在並且可讀 test –s File 文件存在並且是一個套接字 test –t FD 文件描述符是在一個終端打開的 test –u File 文件存在並且設置了它的set-user-id位 test –w File 文件存在並且可寫 test –x File 文件存在並且可執行
真題17、Bourne shell(bash)中有哪些特殊的變數?
答案:下面列出了Bourne shell為命令行設置的特殊變數:
$0 命令行中的腳本名字 $1 第一個命令行參數 $2 第二個命令行參數 ….. ……. $9 第九個命令行參數 $# 命令行參數的數量 $* 所有命令行參數,以空格隔開
真題18、在SHELL腳本中,如何測試文件?
答案:test命令可以用來測試文件。基礎用法如下所示:
-d 文件名 如果文件存在並且是目錄,那麼返回true -e 文件名 如果文件存在,那麼返回true -f 文件名 如果文件存在並且是普通文件,那麼返回true -r 文件名 如果文件存在並可讀,那麼返回true -s 文件名 如果文件存在並且不為空,那麼返回true -w 文件名 如果文件存在並可寫,那麼返回true -x 文件名 如果文件存在並可執行,那麼返回true
真題19、在SHELL腳本中,如何寫入注釋?
答案:注釋可以用來描述一個腳本可以做什麼和它是如何工作的。每一行注釋以#開頭。例子如下:
#!/bin/bash # This is a command echo 「I am logged in as $USER」
真題20、如何讓 SHELL 就腳本得到來自終端的輸入?
答案:read命令可以讀取來自終端(使用鍵盤)的數據。read命令得到用戶的輸入並置於給出的變數中。例子如下:
# vi /tmp/test.sh #!/bin/bash echo 'Please enter your name' read name echo "My Name is $name" # ./test.sh Please enter your name lhr My Name is lhr
真題21、如何取消變數或取消變數賦值?
答案:「unset」命令用於取消變數或取消變數賦值。語法如下所示:
# unset <變數名> 例如: [oracle@lhrxxtoracle ~]$ echo $ORACLE_SID lhrdb [oracle@lhrxxtoracle ~]$ unset ORACLE_SID [oracle@lhrxxtoracle ~]$ echo $ORACLE_SID [oracle@lhrxxtoracle ~]$
真題22、如何執行算術運算?
答案:有兩種方法來執行算術運算:
1.使用expr命令
[oracle@e-e-oracle ~]$ expr 5 + 2 7
2.用一個美元符號和方括弧($[ 表達式 ]),例如:
[oracle@lhrxxtoracle ~]$ test=$[16 + 4] [oracle@lhrxxtoracle ~]$ echo $test 20
真題23、do-while語句的基本格式是什麼?
答案:do-while語句類似於while語句,但檢查條件語句之前先執行命令。do-while語句的語法:
do { 命令 } while (條件)
真題24、在SHELL腳本中如何定義一個函數?
答案:函數是擁有名字的程式碼塊,示例如下所示:
[ function ] 函數名 [()] { 命令; [return int;] }
真題25、如何統計文件a.txt有多少非空行?
答案:
grep -c '^..*$' a.txt 或 grep -v '^$' a.txt | wc -l
真題26、文件b.txt,每行以「:」符分成5列,如「1:apple:3:2012-10-25:very good」,如何得到所有行第三列的總合值?
答案:
awk 'BEGIN {FS=":"; s=0} {s+=$3} END {print s}' b.txt
真題27、取文件c.txt的第60至480行記錄,忽略大小寫,統計出重複次數最多的那條記錄,及重複次數。
答案:
sed -n '60,480'p c.txt | sort | uniq -i -c | sort -rn | head -n 1
真題28、如何生成日期格式的文件?
答案:在Linux/Unix上,使用「`date +%y%m%d`或$(date +%y%m%d)」,如:
touch exp_table_name_`date +%y%m%d`.dmp DATE=$(date +%y%m%d)
或者:
DATE=$(date +%Y%m%d --date '1 days ago') #獲取昨天或多天前的日期
在Windows上,使用%date:~4,10%,其中4是開始字元,10是提取長度,表示從date生成的日期中,提取從4開始長度是10的串。如果想得到更精確的時間,那麼在Windows上面還可以使用time。
真題29、如何測試磁碟性能?
答案:用類似如下的方法測試寫能力:
time dd if=/dev/zero of=/oradata/biddb/testind/testfile.dbf bs=1024000 count=1000
期間系統I/O使用可以用iostat:
iostat -xnp 2 #顯示Busy程度
真題30、如何格式化輸出結果?
答案:可以使用column命令,如下所示:
[oracle@rhel6lhr ~]$ mount /dev/sda2 on / type ext4 (rw) proc on /proc type proc (rw) sysfs on /sys type sysfs (rw) devpts on /dev/pts type devpts (rw,gid=5,mode=620) tmpfs on /dev/shm type tmpfs (rw,size=2G) [oracle@rhel6lhr ~]$ mount | column -t /dev/sda2 on / type ext4 (rw) proc on /proc type proc (rw) sysfs on /sys type sysfs (rw) devpts on /dev/pts type devpts (rw,gid=5,mode=620) tmpfs on /dev/shm type tmpfs (rw,size=2G) [oracle@rhel6lhr ~]$ cat /etc/passwd root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin [oracle@rhel6lhr ~]$ cat /etc/passwd | column -t -s: root x 0 0 root /root /bin/bash bin x 1 1 bin /bin /sbin/nologin
真題31、找出某個路徑下以.conf結尾的文件,並將這些文件進行分類。
答案:可以通過使用xargs這個命令,將命令輸出的結果作為參數傳遞給另一個命令。最終命令為:「find /home/oracle -name *.conf -type f -print | xargs file」,輸出結果如下所示:

xargs後面不僅僅可以加文件分類的命令,還可以加其它的很多命令,比如說實在一點的tar命令。可以使用find命令配合tar命令,將指定路徑的特殊文件使用find命令找出來,然後配合tar命令將找出的文件直接打包,命令如下:
# find / -name *.conf -type f -print | xargs tar cjf test.tar.gz
真題32、如何找出記憶體消耗最大的進程,並從大到小進行排序?
答案:命令為:ps -aux | sort -rnk 4 | head -20,結果如下所示:

輸出的第4列就是記憶體的耗用百分比。最後一列就是相對應的進程。
也可以使用top命令,步驟如下:
① 在命令行提示符執行top命令
② 輸入大寫P,則結果按CPU佔用降序排序。輸入大寫M,結果按記憶體佔用降序排序。
真題33、如何找出CPU消耗最大的進程,並從大到小進行排序?
答案:命令為:ps -aux | sort -rnk 3 | head -20,結果如下所示:

輸出的第3列就是CPU的耗用百分比。最後一列就是相對應的進程。
也可以使用top命令,步驟如下:
① 在命令行提示符執行top命令
② 輸入大寫P,則結果按CPU佔用降序排序。輸入大寫M,結果按記憶體佔用降序排序。
真題34、如何持續ping百度的地址並將結果記錄到日誌?
答案:使用如下命令,輸出的結果會記錄到/tmp/pingbd.log中,每秒鐘新增一條ping記錄:
ping www.baidu.com | awk '{ print $0" " strftime("%Y-%m-%d %H:%M:%S",systime()) }' >> /tmp/pingbd.log &
真題35、如何查看tcp連接狀態?
答案:使用netstat命令,如下所示:
[root@rhel6lhr ~]# netstat -nat | awk '{print $6}'|sort|uniq -c|sort -rn 24 LISTEN 15 ESTABLISHED 1 TIME_WAIT 1 Foreign 1 established) 1 CLOSE_WAIT
真題36、如何查找80埠請求數最高的前20個IP地址?
答案:有時候業務的請求量突然上去了,那麼這個時候可以查看下請求來源IP情況,如果是集中在少數IP上的,那麼可能是存在攻擊行為,需要使用防火牆進行封禁。命令如下:
netstat -anlp|grep 80|grep tcp|awk '{print $5}'|awk -F: '{print $1}'|sort|uniq -c|sort -nr|head -n20
結果如下所示:

真題37、如何使用SHELL腳本來查看多個伺服器的埠是否打開?
答案:在配置伺服器的時候,需要經常查看伺服器的某個埠是否已經開放。如果伺服器只有一兩台的話,那麼只需要使用nc命令查看即可。但是,如果有很多個伺服器的話,那麼在這種情況下,可以使用SHELL腳本配合nc命令來檢查埠的開放情況。不管伺服器有幾台,需要檢查的埠有幾個,使用SHELL腳本都可以實現。
nc是英文單詞netcat的縮寫,它是通過使用TCP或UDP的網路協議的連接來讀或寫數據,可以直接被第三方程式或腳本直接調用。同時,它是一款功能非常強大的網路調試工具,因為它可以創建幾乎所有需要的連接方式。
nc工具主要有三種功能模式:連接模式、監聽模式和通道模式。它的一般使用格式如下:
nc [-options] [HostName or IP] [PortNumber]
其中一些參數的已:
-g<網關>:設置路由器躍程通訊網關,最多設置8個 -G<指向器數目>:設置來源路由指向器,其數值為4的倍數 -h:在線幫助 -i<延遲秒數>:設置時間間隔,以便傳送資訊及掃描通訊埠 -l:使用監聽模式,監控傳入的資料 -n:直接使用IP地址,而不通過域名伺服器 -o<輸出文件>:指定文件名稱,把往來傳輸的數據以16進位字碼傾倒成該文件保存 -p<通訊埠>:設置本地主機使用的通訊埠 -r:指定源埠和目的埠都進行隨機的選擇 -s<來源位址>:設置本地主機送出數據包的IP地址 -u:使用UDP傳輸協議 -v:顯示指令執行過程 -w<超時秒數>:設置等待連線的時間 -z:使用0輸入/輸出模式,只在掃描通訊埠時使用
例如:
[root@rhel6lhr home]# nc -zvw3 192.168.59.130 22 Connection to 192.168.59.130 22 port [tcp/ssh] succeeded! [root@rhel6lhr home]# nc -zvw3 192.168.59.130 1521 Connection to 192.168.59.130 1521 port [tcp/ncube-lm] succeeded!
(1) 使用SHELL腳本完成情景一:掃描多台伺服器的一個埠是否打開。
先把需要查詢的所有伺服器地址全部放在一個server-list.txt文件里,每個地址單獨一行,如下所示:
# cat server-list.txt 192.168.1.2 192.168.1.3 192.168.1.4 192.168.1.5
然後再用for循環依次掃描server-list.txt里對應伺服器的埠是否打開,SHELL腳本(port_scan.sh)如下所示:
#!/bin/sh for server in `more server-list.txt` do nc -zvw3 $server 22 done
再然後,給這個腳本賦予可執行許可權即可:
$ chmod +x port_scan.sh
最後,就可以用這個腳本來自動依次檢查多個伺服器的22埠是否已打開:
# sh port_scan.sh Connection to 192.168.1.2 22 port [tcp/ssh] succeeded! Connection to 192.168.1.3 22 port [tcp/ssh] succeeded! Connection to 192.168.1.4 22 port [tcp/ssh] succeeded! Connection to 192.168.1.5 22 port [tcp/ssh] succeeded!
(2) 使用SHELL腳本完成情景二:掃描多台伺服器的多個埠是否打開。
先把需要查詢的所有伺服器地址全部放在一個server-list.txt文件里,每個地址單獨一行,如下所示:
# cat server-list.txt 192.168.1.2 192.168.1.3 192.168.1.4 192.168.1.5
與此同時,把需要查詢的伺服器埠放在另一個port-list.txt文件里,每個埠單獨一行,如下所示:
# cat port-list.txt 22 80
然後,再用for循環依次掃描server-list.txt里對應伺服器port-list.txt所列的埠是否打開。需要注意的是,此時應該使用兩個for循環,第一層是伺服器列表,第二層是埠列表,SHELL腳本(multiple_port_scan.sh)如下所示:
#!/bin/sh for server in `more server-list.txt` do for port in `more port-list.txt` do nc -zvw3 $server $port echo "" done done
再然後,給這個腳本賦予可執行許可權即可。
$ chmod +x multiple_port_scan.sh
最後,就可以用這個腳本來自動依次檢查多個伺服器的多個埠是否已打開:
# sh multiple_port_scan.sh Connection to 192.168.1.2 22 port [tcp/ssh] succeeded! Connection to 192.168.1.2 80 port [tcp/http] succeeded! Connection to 192.168.1.3 22 port [tcp/ssh] succeeded! Connection to 192.168.1.3 80 port [tcp/http] succeeded! Connection to 192.168.1.4 22 port [tcp/ssh] succeeded! Connection to 192.168.1.4 80 port [tcp/http] succeeded! Connection to 192.168.1.5 22 port [tcp/ssh] succeeded! Connection to 192.168.1.5 80 port [tcp/http] succeeded!
本文選自《Oracle程式設計師面試筆試寶典》,作者:小麥苗