Shell Script


記錄一些 Unix/Linux 常用的 shell and script 概念.

login and non-login shell

登入 shell 分兩種狀態,分別是 login shellnon-login shell.

  1. login shell: 需要打 id/pwd 的
    • login shell 會依序讀取:
      1. /etc/profile
      2. ~/.bash_profile
      3. ~/.bash_login
      4. ~/.profile
    • 後面三個是使用者的設定, 只要找到其中一個, 其他的就不會讀.
  2. non-login shell: 已經在 X-Window 裡了, 不需要登入動作, 或者像是執行 cron job.
    • 依序讀取: /etc/bashrc -> ~/.bashrc
  3. source /etc/profile: 用來重新載入這些設定, 而不需要重新開 shell, 像是跑 cron job, 需要用到完整的訊息, 我就會這樣寫, 以下是每天自動開關 AWS Instance 的例子:
1
2
3
4
5
6
7
8
# Boot/Shutdown AWS Instance
40 7 * * 1-5 source /etc/profile; /opt/aws/ec2-api-tools/1.7.1.0/bin/ec2-start-instances -O xxx -W yyy --region ap-northeast-1 i-xyz
45 7 * * 1-5 source /etc/profile; /opt/aws/ec2-api-tools/1.7.1.0/bin/ec2-start-instances -O xxx -W yyy --region ap-northeast-1 i-xyz
30 19 * * 1-5 source /etc/profile; /opt/aws/ec2-api-tools/1.7.1.0/bin/ec2-stop-instances -O xxx -W yyy --region ap-northeast-1 i-xyz

# Backup database
0 0 * * * source /etc/profile; /root/bin/backup_db.sh
0 1 * * 1-5 find /home/backup/mysql -mtime +90 -delete

使用 crontab 的注意事項

ubuntu 裡,可以直接在 crontab 裡直接附加環境變數,像是:

1
2
APP_HOME=/usr/local/bin/app1
40 7 * * 1-5 /path/script.sh

這樣 script.sh 就可以直接使用。

但是在 centos 裡的無法這樣使用,所以一般會把環境變數在 script 裡宣告。

crontab 的 debug 最常遇到的問題就是手動跑 script 沒問題,進入 crontab 跑問題就一堆,而且通常都不知道原因在哪。

debug 的方法很簡單,寫一個 script 如下:

1
2
3
4
5
#!/bin/sh
date >> /tmp/test.sh
env >> /tmp/test.sh
whoami >> /tmp/test.sh
pwd >> /tmp/test.sh

確認這裡的東西是正常的,如預期的。問題通常都在這裡。

stdin / stdout / stderr

  • stdin: 代碼 0 或者用 < or <<
  • stdout: 代碼 1, 或者用 > or >>
  • stderr: 代碼 2, 或者用 2> or 2>>
    • 只顯示 stdout, 將 stderr 的訊息丟掉: commd 2> /dev/null
  • 將 stdout / stderr 資料都寫入同一個檔案, 兩種寫法:
    1. cmd > log 2>&1, ex: find /Users/ -name > /tmp/log 2>&1
    2. cmd &> log, ex: find /Users/ -name &> /tmp/log

Environment Variables

一些隱含的環境變數,經常在 shell script 使用, 打 set or env 可以看到一堆. env: 只會列出環境變數, set 除了環境變數, function 也會列出來.

  • $$: 顯示目前的 PID (Process ID)
  • cd -: 上一個執行的路徑, 等於 cd $OLDPWD
  • cd ~: 表示 cd $HOME

return code

  • $?: 上一個 command 的 return code,
    • rc = 0: 沒有 exception or error
    • rc > 0: 執行結果問題, 參考 man command 的說明

Return code 可以搭配 &&, || 使用, 也就是連續執行 command 後, 會依據 rc 結果判斷是否繼續執行.

  • cmd1 && cmd2: cmd1 結果 (rc) 為 0, 才繼續執行 cmd2
  • cmd1 || cmd2: cmd1 結果為 0, cmd2 不會繼續執行
  • cmd1; cmd2: 依序執行 cmd, 不管結果如何

history

unix base 大多支援 cli 的 history, 善用它可以解省很多敲字,增加工作效率。

  • history: 顯示歷史指令, 每個指令前面都會有序號,可以透過 !{N} 直接執行
  • control + r: 用關鍵字搜尋歷史
  • 可以設定 history 顯示的格式,在 ~/.bashrc 加入以下,就會顯示日期和時間
1
2
# format of history
export HISTTIMEFORMAT='%F %T '

參考資料

Updated

  • 2017/05/27: Add history, crontab

Comments