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阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容