shell 编程教程

# 变量和值

variables are referenced by $var or ${var}. Global variables are visible to all sub bash sessions, and are often called env variables, local variables are only visible to local session, not subsessions.

Global variables can be viewed as `env`, and can be created by `export`.

TEST=testing; export $TEST # or
export TEST=testing # NOTE: no $

## Useful variables

HOME Same to ~
PATH Search path
EUID User id
GROUPS Groups for current user

## 定义和使用变量

定义变量,注意因为 shell 中的语法使用空格作为命令分割的限制,等于号前后不能加空格。


使用变量,需要添加上 `$` 符号。

echo $FOO


echo "${FOO}xxx"

变量默认实在当前的回话中可见的,而不会作为环境变量传递给调用的命令。可以使用 export 导出变量,或者在命令前加上指定的环境变量。

-> % cat
import os
print('FOO env variable is: ', os.environ.get('FOO'))

-> % python3
FOO env variable is: None

-> % FOO=bar python3
FOO env variable is: bar

使用 export

-> % export FOO=bar
-> % python3
FOO env variable is: bar

## 一些有用的内置变量

$HOME 家目录,比如 /home/kongyifei
$IFS 默认的分隔符,和 for 循环紧密相关
$PATH 搜索路径,当你执行 ls 的时候,shell 会在这个变量中查找 ls 命令
$EUID 当前有效用户 ID
$OLDPWD 上一个工作目录
$PWD 当前工作目录


## 数组

使用小括号来定义一个数组,关于 for 循环随后会讲

A=(1 2 3)

for el in ${A[@]}; do
echo $el

## 字符串操作


% echo {1,2,3,4}
1 2 3 4
% mkdir -p test/{a,b,c,d}{1,2,3,4}
% ls test/
a1  a2  a3  a4  b1  b2  b3  b4  c1  c2  c3  c4  d1  d2  d3  d4
% mv test/{a,c}.conf # 这个命令的意思是:mv test/a.conf test/c.conf

切片: `${string:start:length}`

默认值 `${var:-default}`

设定值 `${var:=default}`

长度 `${#var}`

### 字符串 Expansion and slice

[zorro@zorrozou-pc0 bash]$ mkdir -p test/zorro/{a,b,c,d}{1,2,3,4}
[zorro@zorrozou-pc0 bash]$ ls test/zorro/
a1  a2  a3  a4  b1  b2  b3  b4  c1  c2  c3  c4  d1  d2  d3  d4

[zorro@zorrozou-pc0 bash]$ mv test/{a,c}.conf
这个命令的意思是:mv test/a.conf test/c.conf

${string:start :length} string slice

default value: ${var:-default}
set value: ${var:=default}

${#var} get variable length

# Redirection

input: <, output >, append >>

cat > file << EOF this line will be redirected to file EOF # pipe pipe commands will be run simultaneously, but the second command will wait for the input # Sub shell use $(expression) # 控制语句 ## 条件语句 if 语句成立的条件是 `expr` 返回值为 0。 ``` if expr; then statement; elif expr; then statement; else statement; fi ``` ## test command 虽然可以使用任意的语句作为判断条件,不过我们一般情况下都是用 `[` 这个命令来作为判断条件的,需要注意的是 `[` 并不是一个语法,而是一个命令。不过由于 `[` 这个上古命令实在功能太少,现在一般采用 `[[` 来作为判断条件。 ``` if [[ "a" == "b" ]]; then echo "wtf" else echo "meh" fi ``` `[[`支持的条件有 1 数值比较, 仅限整数,注意不能使用 `>` `<` 等符号。 ``` n1 -eq n2 equal n1 -ge n2 greater or equal n1 -gt n2 greater n1 -le n2 less or equal n1 -lt n2 less n1 -ne n2 not equal ``` 2 字符串比较 Note: Variables may contain space, so the best way to comparison is to add quotes: `"$var1" = "$var2"` ``` str1 == str2 equal str1 != str2 not equal str1 < str2 less str1 > str2 greater -z str zero -n str not zero length ``` 3 file comparison -d is directory? -e exist? -f is regular file? -r exist and readable? -s exist and has content -w exist and writable -x exist and executealbe -O exist and owned -G exist and in same group file -nt file2 newer than file1 -ot file2 older than ## case case var in parttern | pattern2) commands;; pattern3) commands2; *) default commnads;; esac ## Loops ### foreach 语句 for var in list; do echo $var done 其中 list 可以是一个数组,也可以是一个被 $IFS 分割的字符串。默认情况下,$IFS 是 " \n\t"。其中包含了空格。 如果要覆盖 IFS,一般这样使用: OLDIFS=$IFS IFS="\n" # new seperator # do things IFS=$OLDIFS ### while-loop until/while expr; do # commands done ### pipe the result of a for loop is pipe-able to other command ``` for city in beijing shanghai; do echo $city is big done > cities.txt # will save the result in cities.txt ``` # 输入输出 ## 命令行参数 parameters to a script can be obtained as $1, $2, $3...。 $0 is the script name, remember to check whether the parameter is empty. $# is the number of parameters(without script name). ``` $0 script name / function name $1...$x command line arguments / parameters $# number of arguments(without $0) $* all parameters as a string $@ all parameters as a string list ``` ### shift processing parameters using shift, while [ -n "$1" ]; do case "$1" in -a) echo "option -a" ;; --) shift break;; *) echo "$1" is not a option ;; esac shift done ## read read OPTIONS VARNAME read input to variables - read -p Prompt - read -t timeout - read -s hide input we can use read to read file or stdin ## redirection 2> redirect STDERR
m>&n redirect fd m to fd n’s associated file

Note: you have to use command >> command.log 2>&1 (put 2>&1 at the end), since this means redirect 2 to 1’s
in a scirpt
exec 2> filename # reopen stdout to filename

# Signal

trap commnad signal is used to handle signals in shell

# Functions


function name {
# function body

foo() {
# function body




## return

shell functions behave like a small script, and it does NOT return a computed value…It retures a exit code, which is between 0 and 255. if no return is specified, the exit code of last command will be returned

You can read the return value by $? like any normal commands

the right way to to return a value from function, you will have to echo out the value, and put the function is subshell

function foo {
# do some compute
echo $result;


Note: any thing that echos in the function body will be captured, so please keep that from happen

## parameters

like a shell script, $0 holds the function name, $1 … $9 holds the parameters, $# is the num of parameters

## local variables

use `local` to declare local variables

# alias

alias new_name='command string'
$ \command # bypass alias

# debugging

DEBUG macro

# multiprocess

for file in filelist; do
md5sum file &;
wait ${PID_ARRAY[@]}



About 逸飞



电子邮件地址不会被公开。 必填项已用*标注