bash 腳本要點、sed、awk、grep

bash:Bourne Again shell,是 Linux 上的標配 shell;對于想學習 shell 的人來說,無論是新手,還是想進一步提高 shell 編程能力的高級用戶,bash 都是比較好的選擇。

  1. For learning Bash, try the BashGuide.
  2. 引號 Quotes,熟讀并測試!
  3. 命令參數 Arguments,熟讀并測試!
  4. Word Splitting
  5. Process Management,有價值!

grep

小技巧

  • cat - > /tmp/xxx,或者 echo "$(</dev/stdin)" > /tmp/xxx 將標準輸入(屏幕輸入)直接輸出到xxx文件中。使用 ctrl+d 中止輸入。How to redirect stdin to file in bash

條件判斷

  • Introduction to if
    [ "$a" \> "$b"]字符串比較大小;>< 是重定向字符,做大小比較時,要轉義。文件是否存在等。
    [ -s "$filename" ][ -d "$filename" ][ -L "$filename" ][ ! -e "$filename" ] 判斷文件、目錄、鏈接,必須雙引號括起;
    [ -z "$name" ][ -n "$name" ] 判斷字符串長度,必須雙引號括起;
  • if TEST-COMMANDS; then CONSEQUENT-COMMANDS; fi
    The TEST-COMMAND list is executed, and if its return status is zero, the CONSEQUENT-COMMANDS list is executed. The return status is the exit status of the last command executed, or zero if no condition tested true.
  • Testing and Branchingelif
if [  ]; then
...
elif [  ]; then
...
else
...
fi
case $HOST in node*)
    your code here
esac
  1. script_dir=$( cd ${0%/*} && pwd -P ) 文件目錄【從右側開始刪除,直到遇到第一個 /:最短刪除】
  2. ${0##*/},相當于 "$(basename ${0})" 文件名【從左側開始刪除,直到最后一個/:最長刪除】
  3. g_nap=${url##*/}; g_nap=${g_nap%%\?*} 取 url 的 path 的最右側一節;http://host:port/p1/p2/p3?query,取到的是p3;
計算賦值
i=0
i=$(expr $i + 1)
i=`expr $i + 1`
i=$(($i + 1))
i=$[$i + 1]
i=$((i + 1))
i=$[i + 1]

讀文件

  • 數組
    ${#ArrayName[@]}:顯示數組大小。
  • ${ArrayName[@]} 數組的所有值。
  • "${ArrayName[$i]}" 取數組第i個值。
  • NEW=("${OLD1[@]}" "${OLD2[@]}"): 將兩個數組合并生成一個新數組。
  • 給定一個值,看是否在數組中存在
if [[ ! " ${PART_OPTS[*]} " =~ " ${PART} " ]]; then
    echo -e "\e[41m PART:$PART 錯誤,目前僅支持 ${PART_OPTS[*]} \e[0m"; exit 99;
fi
IN="bla@some.com;john@home.com"
arrIN=(${IN//;/ })
echo ${arrIN[1]}  
for element in "${array[@]}"
do
    echo "$element"
done
for index in "${!array[@]}"
do
    echo "$index ${array[index]}"
done

結構良好

  1. $(command)
  2. `command`
  3. $(...) is preferred over `...` (backticks),建議使用 $(...);
  • 注意:${}$()$[] 的用法。
  • 注意某些嵌入系統要求嚴格,數字變量初值賦數字,保持可移植性;
  • echo 輸出內容使用 "" 雙引號括起,某些嵌入系統要求嚴格;
    類似 echo "who am I: $USER",如果沒有雙引號,$USER 輸出可能就為空;$USER 是一個內置變量;
  • IFS:Internal Field Separator,Input Field Separator;
    The default value of IFS is space, tab, newline. (A three-character string.)
    在 shell 腳本中,一般沒有必要修改 IFS。
  • Arithmetic expansion
$(( EXPRESSION ))
$[ EXPRESSION ]

If a command is terminated by the control operator ‘&’, the shell executes the command asynchronously in a subshell. This is known as executing the command in the background. The shell does not wait for the command to finish, and the return status is 0 (true).

if [ "$EUID" -ne 0 ]; then
  echo "Please run as root"
  exit
fi

變量、函數和引號

The shell parses your command-line into a command name and a list of arguments. 
It uses white-space (tabs and spaces) to split the command into these parts.
Then it runs the command, passing it the argument list.

Perl one-liner 這個工具也很有用,可以分析參數。Smylers 是個人物。

錯誤

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 status is 126.
比如:試圖在 64 位機上 運行 ELF 32 位可執行程序,則報告如下錯誤:

./superd -V
-bash: ./superd: cannot execute binary file
echo $?
126

雙引號

命令

  • Get current users username in bash
    whoami$USER 查看當前用戶
  • source 命令或者 . 命令
    source <filename>
    . <filename>.命令是POSIX 標準)這里的 . 和 source 一樣,都是內置命令;注意區分命令的 . 和表示目錄的 .
    source 執行文件時,不要求文件有可執行屬性 +x;
    source 引入(包含)的文件如何處理 arguments 的?

subshell

  • sh <filename>,不要求 filename 有可執行權限;
  • ./filename,要求 filename 有可執行權限;
  • 內置命令執行shell腳本文件
    shell 內置命令(builtin)不會開啟 subshell。
  • command, type, hash
    How to check if a program exists from a Bash script?

awk | gawk

sed -n '$=' filename
awk 'END {print NR}' filename
grep -c '' filename
  • AWK - Built-in Functions @tutorialspoint.com 是一個非常好的 AWK 學習材料,值得從頭到尾讀一遍,你就是 awk 專家了;

  • how to use awk to manipulate textlearning-awk
    這是非常好的文章,循序漸進,容易理解和學習使用。
    The basic format of an awk command is:
    awk '/search_pattern/ { action_to_take_on_matches; another_action; }' file_to_parse
    --field-separator 或者 -F 則指定使用什么作為分隔符
    示例:
    echo "a/b/c" | awk '{print $0}'$0 輸出的是原始文本 a/b/c$1 就是空格分隔的第1個值,也是 a/b/c$2 及以后就為空。
    echo "a/b/c" | gawk -F "/" '{print $2}',結果顯示 b;
    gawk '/^author/ { print $0 }' onefile,找出文件 onefile 中以 author 開頭的行,并打印整行;

  • $(awk -v s="$v" 'BEGIN {gsub("=", "", s); gsub("&", "", s); gsub(" ", "", s); print substr(s, 1, 24)}');
    變量v賦值給s,替換s中的=&空格,僅取s的前24個字符;

  • awk 的 print 語句

  • How to print third column to last column?: 處理文件行內容,打印出第3列到最后一列的所有內容。

# 分隔符為空格
cut -d ' ' -f 3- <filename>
# 或者采用 awk

命令行參數

for last; do true; done
echo $last
如何異步簽出代碼并構建?

source /home/git/devops/gwph.git.hooks/www.post-receive.gulp >&- 2>&- &

何為重定向?

符號 & 比較神奇,在命令后面加 & 就會在后臺運行;還可以用來重定向,原來一直對重定向模糊,今天前端構建時要在簽入代碼之后異步構建頁面,看了兩篇文章才徹底明白其原理:

if cmp a b &> /dev/null  # Suppress output.
then echo "Files a and b are identical."
else echo "Files a and b differ."
fi
bash shell 特殊變量
No. Variable Description
1 $0 The filename of the current script.
2 $n These variables correspond to the arguments with which a script was invoked. Here n is a positive decimal number corresponding to the position of an argument (the first argument is $1, the second argument is $2, and so on).
3 $# The number of arguments supplied to a script.
4 $* All the arguments are double quoted. If a script receives two arguments, $* is equivalent to $1 $2.
5 $@ All the arguments are individually double quoted. If a script receives two arguments, $@ is equivalent to $1 $2.
6 $? The exit status of the last command executed.
7 $$ The process number of the current shell. For shell scripts, this is the process ID under which they are executing.
8 $! The process number of the last background command.

The exit command in bash accepts integers from 0 - 255, in most cases 0 and 1 will suffice, however there are other reserved exit codes that can be used for more specific errors. The Linux Documentation Project has a pretty good table of reserved exit codes and what they are used for.
保留錯誤碼。錯誤碼在 1-255 之間。用戶使用的話,建議在 1-125 之間取值。

備注

Read and execute commands from filename in the current shell environment and return the exit status of the last command executed from filename.
If any arguments are supplied, they become the positional parameters when filename is executed.
Otherwise the positional parameters are unchanged.
The return status is the status of the last command exited within the script (0 if no commands are executed),
and false if filename is not found or cannot be read.

字符串比較請使用一個等號=即可(POSIX標準)
[ STRING1 == STRING2 ]  True if the strings are equal. "=" may be used instead of "==" for strict POSIX compliance.
使用superctl_ok.sh更合適

BASH 基本概念

Bash Component Architecture @ aosabook.org
Brace Expansion:{} 擴展;
Tilde Expansion:~ 擴展;
Variable and Parameter Expansion(PE):變量和參數擴展;
  • 理解 Parameter Expansion 這個概念很重要;
  • 理解:literal 和 syntactic,尤其:空白符引號反斜線 在何時是 syntactic?
  • Variables are a common type of parameter.

It is vital to understand, however, that Quoting and Escaping are considered before parameter expansion happens, while Word Splitting is performed after. That means that it remains absolutely vital that we quote our parameter expansions, in case they may expand values that contain syntactical whitespace which will then in the next step be word-split.

  • Command, Process, Arithmatic Substitution:命令、進程、算數替換;
  • Word Splitting:分詞,Field Splitting;理解 IFS
  • Filename Generation:文件名生成;
  • Shell Expansions:基礎知識,值得讀,詳細解釋了以上各種擴展和替換;
解析流程
eval 050 規則
Greg's Wiki【wooledge.org】
  1. 首先理解系統調用 execve
    int execve(const char *filename, char *const argv[], char *const envp[]);
    argv:argument vector;
    envp:environment;
  2. 理解 shell 如何將 命令 command 翻譯成系統調用;
  3. 實現業務邏輯;
Quote Guidelines
  • quoting in shell programming is extremely important.
  • "Quote" any arguments that contain data which also happens to be shell syntax.
  • "$Quote" all parameter expansions in arguments. You never really know what a parameter might expand into; and even if you think it won't expand bytes that happen to be shell syntax, quoting will future-proof your code and make it safer and more consistent.
  • Don't try to put syntactical quotes inside parameters. It doesn't work.
了解 shell
知識點
  • 文件大小
    ls -l filename |awk '{print $5}'
    wc -c < filename:short for word count, -c prints the byte count. wc is a portable, POSIX solution.
    du -k filename | cut -f1
  • cat <<EOF
    How does “cat << EOF” work in bash

示例:
cat <<EOF
Usage: $0 [options]
Language-agnostic unit tests for subprocesses.
Options:
-v, --verbose generate output for every individual test case
-h show brief usage information and exit
--help show this help message and exit
EOF

  • 查看 bash 版本
    /bin/bash --version
    echo $BASH_VERSION

sudo bats 時報告sudo: bats: command not found

$ sudo bats sapiloader.bats
sudo: bats: command not found

解決方案

The error happens because the binary you are trying to call from command line is only part of the current user's PATH variable, but not a part of root user's PATH.
$ sudo env | grep ^PATH 查看 sudo 的 PATH,果然發現不包含 /usr/local/bin,因此:將 bats 改為全路徑 /usr/local/bin/bats 就可以正常執行,但不方便,我們改造 ~/.bashrc,加一條語句,創建 sudo 別名(別名優先于命令)即可:
alias sudo='sudo -E env "PATH=$PATH"'
完美解決!

備注

  • 錯誤 [: bad number 的問題原因是:[ $EUID -eq 0 ] 語句中,EUID 沒有賦值,在有些 shell 中 EUID 是內部變量,會自動賦值,你在 script 中使用即可,但有些就沒有賦值,所以不要使用。但從用法上可以這么解決:${EUID:-0},采用 Parameter Substitution default 值來避免錯誤,當 EUID 未聲明或者賦值為空時,輸出 0。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,182評論 6 543
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,489評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,290評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,776評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,510評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,866評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,860評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,036評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,585評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,331評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,536評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,058評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,754評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,154評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,469評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,273評論 3 399
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,505評論 2 379

推薦閱讀更多精彩內容