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 ~
IFS
PATH Search path
EUID User id
GROUPS Groups for current user
HOSTNAME Hostname
LANG
LC_ALL
OLDPWD
PWD
“`

## 定义和使用变量

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

“`
FOO=bar
“`

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

“`
echo $FOO
“`

字符串在双引号中可以直接插入,这时候要加上大括号来指示变量名的起始位置。

“`
echo “${FOO}xxx”
“`

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

“`
-> % cat env.py
import os
print(‘FOO env variable is: ‘, os.environ.get(‘FOO’))

-> % python3 env.py
FOO env variable is: None

-> % FOO=bar python3 env.py
FOO env variable is: bar
“`

使用 export

“`
-> % export FOO=bar
-> % python3 env.py
FOO env variable is: bar
“`

## 一些有用的内置变量

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

“`

## 数组

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

“`
A=(1 2 3)

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

## 字符串操作

大括号里面的字符串会被展开成独立的字符串

“`
% 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
}
“`

要调用上面这个函数,直接就输入

“`
foo
“`

就好了

## 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;
}

retval=$(foo)
“`

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

PID_ARRAY=()
for file in filelist; do
md5sum file &;
PID_ARRAY+=(“$!”)
done
wait ${PID_ARRAY[@]}

About 逸飞

后端工程师

发表评论

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