shell programming


Author: yifei / Created: July 16, 2017, 9:38 a.m. / Modified: July 16, 2017, 5:39 p.m. / Edit

变量和值

定义和使用变量

定义变量,注意因为 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}

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

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[@]}


评论区