在 bash script 裡,可以用 ${RANDOM}
取亂數,例如
echo "random number: ${RANDOM}"
就會出現一個隨機的數字。
那如果想限制在 20~40 這個範圍內的話,可以怎麼做呢?這時候可以用 bash 的 % ,取餘數的運算子來做,例如
echo "random number(0~10): $((20 + RANDOM % 20))"
Just thinking more…
在 bash script 裡,可以用 ${RANDOM}
取亂數,例如
echo "random number: ${RANDOM}"
就會出現一個隨機的數字。
那如果想限制在 20~40 這個範圍內的話,可以怎麼做呢?這時候可以用 bash 的 % ,取餘數的運算子來做,例如
echo "random number(0~10): $((20 + RANDOM % 20))"
這篇寫的很好,整理並摘錄裡面的內容
#!/usr/bin/env bash
,這樣可以確保都是用相同的 shell 來執行,我自己是都寫 #!/bin/bash
.sh
set -o errexit
,只要裏面有一行錯誤,就離開,不要繼續。set -o nounset
,只要有未設定的變數,就離開,不要繼續。set -o pipefail
,只要 pipe 過程中的指令有錯誤,就離開,不要繼續。set -o xtrace
,這可以幫助除錯。[[ ]]
取代 [ ]
,[[ ]]
是 bash內建的關鍵字,基本上作用跟 []
或 test 一樣,可以減少額外消耗,而且有更多功能。-h
或 --help
來說明自己怎麼使用。echo 'Something unexpected happened' >&2
--silent
代替 -s
,這樣可讀性比較高。cd "$(dirname "$0")"
我想這個應該是要確定腳本所要作用的目錄,所以加上註解,或是印出當前所在目錄,都對於後續維護的人會很有幫助。shellcheck
來檢查腳本作者有提供一個範本,可以直接複製來修改:
#!/usr/bin/env bash
set -o errexit
set -o nounset
set -o pipefail
if [[ "${TRACE-0}" == "1" ]]; then
set -o xtrace
fi
if [[ "${1-}" =~ ^-*h(elp)?$ ]]; then
echo 'Usage: ./script.sh arg-one arg-two
This is an awesome bash script to make your life better.
'
exit
fi
cd "$(dirname "$0")"
main() {
echo do awesome stuff
}
main "$@"
基本上就包含了前面所提到的重點,這裡額外一提的是有 main,這對於理解腳本來說,也是很重要的事情。
我忘記為什麼會要找這個,總之,要檢查檔案不是空的,可以用 -s 。
這用 man test
可以查到, -s 的說明是這樣的:True if file exists and has a size greater than zero.
當檔案存在而且長度大於 0 時,回傳 True。換言之,False 時,就代表檔案的長度是 0 (空的)。
我是在 StackOverflow 找到的:linux – How to check if a file is empty in Bash? – Stack Overflow
if [ -s diff.txt ]; then
# The file is not-empty.
rm -f empty.txt
touch full.txt
else
# The file is empty.
rm -f full.txt
touch empty.txt
fi
一般更新 /etc/sudoers
檔案內容都是使用 visudo
指令進行;若是要管理 sudoer ,Ansible 可以用 community.general.sudoers
模組來管理。
那如果要在腳本裡更新,該怎麼做呢?這時候可以參考 How do I edit /etc/sudoers from a script? 裡的作法來進行。
這作法蠻 tricky 的,主要是利用 EDITOR 環境變數把 visudo 預設的編輯器換為 tee -a
,這樣就不會開啟 vi 編輯器,而會改用 tee 來處理。來看看這行指令
echo 'foobar ALL=(ALL:ALL) ALL' | sudo EDITOR='tee -a' visudo
|
的左邊是很單純的 echo,這裡可以放置要放進去的設定|
的右邊就是 sudo 跟 visudo ,這是用 sudo 執行 visudo 指令,並且把編輯器換為 tee -a
這樣組合以後,就可以把設定放到 /etc/sudoers
裏面去了。
另外一種比較單純的作法就是在 /etc/sudoers.d
目錄下去新增檔案,新增以後,因為 /etc/sudoers
裏面有寫 #includedir /etc/sudoers.d
,所以會引用到 /etc/sudoers.d
目錄下的檔案。
記錄關於 bash argument 的幾則常用語法。
argument 一般翻譯為引數或參數,帶有 — 的,會被稱為選項。
prog arg1 arg2 arg3
prog --output option1 arg1
arg1, arg2, arg3 就是引數;–output option1 就是選項。
寫 shell script 時,是不管 — 的,在 prog 之後的,都叫做引數。以下用法均以 prog arg1 arg2 arg3
作為範例
用法 | 說明 | 結果 |
$# | 取得引數個數 | 3 |
$@ | 所有引數 | arg1 arg2 arg3 |
myArray=(“$@”) | 轉為 Array | 會印出 arg1,要遍訪,需用 for: |
myArray=(“$@”) echo “${myArray}” | 只印出Array第一個元素 | arg1 |
for arg in “${myArray[@]}”; do echo -n “${arg},”; done | 遍訪Array所有元素 | arg1,arg2,arg3, |
myArray=( “$@” ) arraylength=${#myArray[@]} for (( i=0; i<${arraylength}; i++ )); do echo “${myArray[$i]}” done | 遍訪Array所有元素的另一個作法,用索引方式。 | arg1 arg2 arg3 |
if ["$#" -eq 0]; then echo "no argument"; fi | 判斷是有否引數 | 若無引數,印出 “no argument” |
B=(“${myArray[@]:1:2}”) echo “${B[@]}” | 做slice | arg2 arg3 |
version=4.7.1 A=( ${version//./ } ) echo “${A[@]}” | split | 4 7 1 |
a=”HELLO WORLD”echo "${a,,}" echo “${a,,[AEIUO]}” | 轉小寫 | hello world HeLLo WoRLD |
a=”hello world”echo "${a^^}" | 轉大寫 | HELLO WORLD |
atuin 可以把指令歷史改放到 sqlite db 裡,提供了 fancy 的畫面跟功能,還蠻酷的。它在雲端有提供 sync 伺服器,可以把指令同步上去,我本來在想這會有安全疑慮吧,畢竟有些時候指令就會帶密碼。不過,atuin 已經有做加密了,放上去是安全的。
atuin sync 伺服器也可以自行架設,除了可以同步之外, sync 伺服器還有提供一個類似 github graph 的功能,可以看到活動圖,蠻有趣的。
bash <(curl https://raw.githubusercontent.com/ellie/atuin/main/install.sh)
如果想試試預設的 sync 伺服器,就先用 atuin register
來註冊
atuin register -u <USERNAME> -e <EMAIL> -p <PASSWORD>
若不需要,就匯入目前的 history
atuin import auto
如果是使用 bash ,就用以下指令,把設定放到 .bashrc
curl https://raw.githubusercontent.com/rcaloras/bash-preexec/master/bash-preexec.sh -o ~/.bash-preexec.sh
echo '[[ -f ~/.bash-preexec.sh ]] && source ~/.bash-preexec.sh' >> ~/.bashrc
echo 'eval "$(atuin init bash)"' >> ~/.bashrc
若是 zsh ,就改用以下指令,把設定放到 .zshrc 裡
echo 'eval "$(atuin init zsh)"' >> ~/.zshrc
設定好,就關掉終端機,開新的終端機,或者是登出,重新再登入,設定就生效了。
使用很簡單,按下 ctrl+r 或是按上,就會看到 atuin 的畫面,輸入字母,上方就會篩選出相關的指令。
那也可以打指令去找,例如找昨天下午3點以前的 ls 指令
atuin search --exit 0 --after "yesterday 3pm" ls
相當簡單。
架設 sync 伺服器的部份有空再來試好了,目前就先都以本機使用為主。
其實就現在來說,使用 ctrl+r 就已經很方便,而且也不需要安裝,直接就能使用。未來會有需要集中管理指令歷史功能的強烈需求嗎?我想可能是沒有,就先用一陣子試試看好了,一周以後再來評估是否要繼續使用。
Python 的 dict 很方便,寫 bash 時,自然會想 Bash 到底有沒有這個呢?
在 StackOverflow 上找到這篇 How to define hash tables in Bash? ,裏面就介紹了用法:
# Python 語法:animals = {'moo': 'cow', 'woof': 'dog'}
# 宣告1
declare -A animals
animals=( ["moo"]="cow" ["woof"]="dog")
# 宣告2
declare -A animals=( ["moo"]="cow" ["woof"]="dog")
# 取某個鍵對應的內容,跟 Python 的 animals['moo'] 一樣。
echo "${animals[moo]}"
# Iterate
for sound in "${!animals[@]}"; do echo "$sound - ${animals[$sound]}"; done
今天用 sort 去排序月份字串,明明說可以用 -M 來排序,可是實際結果卻不行。使用 –debug 來察看如何排序,卻發現有 “no match for key” 的訊息,這就奇怪了。
找了半天,才找到這篇 bash – Shell sort by month ,才明白這跟 locale 有關係,因為我的 locale 設定為 zh_TW.utf-8 ,sort 在判讀月份時,是使用當地的月份來判讀,而不認英文的月份。解決方法就是加上 LANG 或 LC_TIME 即可:LANG=c sort -k1M your_file
git 沒辦法加空目錄,沒有任何選項可以用。Stackoverflow (How do I add an empty directory to a Git repository? – Stack Overflow) 上提到的變通方法就是為這些空目錄添加一個空白的檔案,檔名看是要用 .gitignore 或是 README 之類的就可以。
那要找所有空目錄的話,該怎麼找?find 就可以做到這點 (參考 bash – finding empty directories unix – Stack Overflow) :
find . -type d -empty -print
那麼,要為每個空目錄加上空白檔案的話,再利用 -exec 參數就可以了:
find . -type d -empty -exec touch {}/README \;