shell编程初步
Posted Overboom
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了shell编程初步相关的知识,希望对你有一定的参考价值。
0. shell的作用
Shell就是命令行工具的胶水,没有任何语言能像Shell一样方便地将一大堆命令行工具组合起来。原则上来说,Shell做什么都可以,但显然它最适合的是自动化,因为只需要将你原来手动敲的命令都复制到一个文件里面就行了。
Shell跟标准的编程语言区别很大,它基本上是一个面向字符串的编程语言,组合用好awk/sed/grep,偶尔配合eval,有时候会发挥奇效。
1. shell基本语法
1.1 变量
按照惯例,Shell变量通常由字母加下划线开头,由任意长度的字母、数字、下划线组成。有两种类型的Shell变量:
1.环境变量
环境变量可以从父进程传给子进程,因此Shell进程的环境变量可以从当前Shell进程传给fork出来的子进程。用printenv命令可以显示当前Shell进程的环境变量。
2.本地变量
只存在于当前Shell进程。
3. 变量赋值
环境变量是任何进程都有的概念,而本地变量是Shell特有的概念。在Shell中,环境变量和本地变量的定义和用法相似。在Shell中定义或赋值一个变量:
VAR_NAME=value
注意等号两边都不能有空格,否则会被Shell解释成命令和命令行参数。
一个变量定义后仅存在于当前Shell进程,它是本地变量,用export命令可以把本地变量导出为环境变量
4. 用unset删除变量
unset VAR_NAME
5. 引用变量
$VAR_NAME
1.2 单引号和双引号
被双引号用括住的内容,将被视为单一字串。它防止通配符扩展,但允许变量扩展。这点与单引号的处理方式不同
1.3 条件测试
shell中提供两种条件判断的方法。
1. test指令
overboom@overboom:~/Work $ var=2
overboom@overboom:~/Work $ test $var -gt 1
overboom@overboom:~/Work $ echo $?
0
overboom@overboom:~/Work $
overboom@overboom:~/Work $
overboom@overboom:~/Work $ test $var -eq 3
overboom@overboom:~/Work $ echo $?
1
overboom@overboom:~/Work $ test $var -eq 2
overboom@overboom:~/Work $ echo $?
0
$? 代表上一个命令执行后的退出状态
2. [ condition ] 注意condition前后要有空格。非空返回0,0为 true,否则为 false 。
overboom@overboom:~/Work$ var=2
overboom@overboom:~/Work$ [ $var -gt 3 ]
overboom@overboom:~/Work$ echo $?
1
overboom@overboom:~/Work$ [ $var -eq 2 ]
overboom@overboom:~/Work$ echo $?
0
overboom@overboom:~/Work$
常见测试指令如下:
[ -d DIR ] 如果DIR存在并且是一个目录则为真
[ -f FILE ] 如果FILE存在且是一个普通文件则为真
[ -z STRING ] 如果STRING的长度为零则为真
[ -n STRING ] 如果STRING的长度非零则为真
[ STRING1 = STRING2 ] 如果两个字符串相同则为真
[ STRING1 != STRING2 ] 如果字符串不相同则为真
[ ARG1 OP ARG2 ] ARG1和ARG2应该是整数或者取值为整数的变量,OP是-eq(等于)-ne(不等于)-lt(小于)-le(小于等于)-gt(大于)-ge(大于等于)之中的一个
3. 条件测试与逻辑运算符
和C语言类似,测试条件之间还可以做与、或、非逻辑运算:
[ ! EXPR ] EXPR可以是上表中的任意一种测试条件,!表示“逻辑反(非)”
[ EXPR1 -a EXPR2 ] EXPR1和EXPR2可以是上表中的任意一种测试条件,-a表示“逻辑与”
[ EXPR1 -o EXPR2 ] EXPR1和EXPR2可以是上表中的任意一种测试条件,-o表示“逻辑或”
1.4 分支结构
1.4.1 if/then/elif/else/fi
和C语言类似,在Shell中用if、then、elif、else、fi这几条命令实现分支控制。
下面看一段示例code
#! /bin/sh
if [ -f /bin/bash ]
then
echo "/bin/bash is a file"
else
echo "/bin/bash is NOT a file"
fi
if :; then echo "always true"; fi
与C类似的语法,并不难理解。
“:”是一个特殊的命令,称为空命令,该命令不做任何事,但Exit Status总是真。此外,也可以执行/bin/true或/bin/false得到真或假的Exit Status。
1.4.2 case/esac
case命令可类比C语言的switch/case语句,esac表示case语句块的结束。C语言的case只能匹配整型或字符型常量表达式,而Shell脚本的case可以匹配字符串和Wildcard,每个匹配分支可以有若干条命令,末尾必须以;;结束,执行时找到第一个匹配的分支并执行相应的命令,然后直接跳到esac之后,不需要像C语言一样用break跳出。
#! /bin/sh
echo "Is it morning? Please answer yes or no."
read YES_OR_NO
case "$YES_OR_NO" in
yes|y|Yes|YES)
echo "Good Morning!";;
[nN]*)
echo "Good Afternoon!";;
*)
echo "Sorry, $YES_OR_NO not recognized. Enter yes or no."
return 1;;
esac
return 0
1.5 循环
1.5.1 for/do/done
Shell脚本的for循环结构和C语言很不一样,它类似于某些编程语言的foreach循环。例如:
#! /bin/sh
for FRUIT in apple banana pear; do
echo "I like $FRUIT"
done
1.5.2 while/do/done
while的用法和C语言类似。比如一个验证密码的脚本:
#! /bin/sh
echo "Enter password:"
read TRY
while [ "$TRY" != "secret" ]; do
echo "Sorry, try again"
read TRY
done
1.5.3 break和continue
break[n]可以指定跳出几层循环;continue跳过本次循环,但不会跳出循环。
即break跳出,continue跳过。
2 位置参数和特殊变量
shell中常用的位置参数和特殊变量总结:
$0 相当于C语言main函数的argv[0]
$1、$2... 这些称为位置参数(Positional Parameter),相当于C语言main函数的argv[1]、argv[2]...
$# 相当于C语言main函数的argc - 1,注意这里的#后面不表示注释
$@ 表示参数列表"$1" "$2" ...,例如可以用在for循环中的in后面。
$* 表示参数列表"$1" "$2" ...,同上
$? 上一条命令的Exit Status
$$ 当前进程号
#!/bin/bash
echo ------start--------
echo $0 $1 $2
echo $*
echo $@
echo $$
echo $#
echo ------end--------
输出如下:
可以在shell脚本中使用shift丢弃一些参数
#!/bin/bash
echo ------start--------
echo ------before shift--------
echo $0 $1 $2 $3 $4 $5
echo $#
shift
shift
shift
echo ------after shift--------
echo $0 $1 $2 $3 $4 $5
echo $#
echo ------end--------
输出如下:
3. 输入和输出
3.1 echo
显示文本行或变量,或者把字符串输入到文件。
echo [option] string
-e 解析转义字符
-n 不回车换行。默认情况echo回显的内容后面跟一个回车换行。
3.2 tee
tee命令把结果输出到标准输出,另一个副本输出到相应文件。
overboom@overboom:~/Work$ ls -al
total 52
drwxrwxr-x 11 overboom overboom 4096 9月 12 22:47 .
drwxr-xr-x 22 overboom overboom 4096 9月 12 22:47 ..
drwxr-xr-x 7 root root 4096 7月 4 18:39 beanCode
drwxrwxr-x 2 overboom overboom 4096 3月 27 23:45 c_code
drwxrwxr-x 3 overboom overboom 4096 8月 10 21:07 fdbus
drwxrwxr-x 3 overboom overboom 4096 8月 10 23:16 git_usage
drwxrwxr-x 4 overboom overboom 4096 6月 2 00:08 jsoncpp
drwxrwxr-x 2 overboom overboom 4096 8月 4 21:20 minixml
-rwxrwxr-x 1 overboom overboom 213 9月 12 22:45 position.sh
drwxrwxr-x 2 overboom overboom 4096 5月 27 23:43 test_C++Sqlite
drwxrwxr-x 6 overboom overboom 4096 5月 25 21:37 test_find
-rwxrwxr-x 1 overboom overboom 141 9月 12 21:23 test.sh
drwxrwxr-x 3 overboom overboom 4096 4月 10 17:36 xwp_linux
overboom@overboom:~/Work$ ls -al | tee out_file
total 52
drwxrwxr-x 11 overboom overboom 4096 9月 12 23:02 .
drwxr-xr-x 22 overboom overboom 4096 9月 12 22:47 ..
drwxr-xr-x 7 root root 4096 7月 4 18:39 beanCode
drwxrwxr-x 2 overboom overboom 4096 3月 27 23:45 c_code
drwxrwxr-x 3 overboom overboom 4096 8月 10 21:07 fdbus
drwxrwxr-x 3 overboom overboom 4096 8月 10 23:16 git_usage
drwxrwxr-x 4 overboom overboom 4096 6月 2 00:08 jsoncpp
drwxrwxr-x 2 overboom overboom 4096 8月 4 21:20 minixml
-rwxrwxr-x 1 overboom overboom 213 9月 12 22:45 position.sh
drwxrwxr-x 2 overboom overboom 4096 5月 27 23:43 test_C++Sqlite
drwxrwxr-x 6 overboom overboom 4096 5月 25 21:37 test_find
-rwxrwxr-x 1 overboom overboom 141 9月 12 21:23 test.sh
drwxrwxr-x 3 overboom overboom 4096 4月 10 17:36 xwp_linux
overboom@overboom:~/Work$ ll
total 56
drwxrwxr-x 11 overboom overboom 4096 9月 12 23:02 ./
drwxr-xr-x 22 overboom overboom 4096 9月 12 22:47 ../
drwxr-xr-x 7 root root 4096 7月 4 18:39 beanCode/
drwxrwxr-x 2 overboom overboom 4096 3月 27 23:45 c_code/
drwxrwxr-x 3 overboom overboom 4096 8月 10 21:07 fdbus/
drwxrwxr-x 3 overboom overboom 4096 8月 10 23:16 git_usage/
drwxrwxr-x 4 overboom overboom 4096 6月 2 00:08 jsoncpp/
drwxrwxr-x 2 overboom overboom 4096 8月 4 21:20 minixml/
-rw-rw-r-- 1 overboom overboom 793 9月 12 23:02 out_file
-rwxrwxr-x 1 overboom overboom 213 9月 12 22:45 position.sh*
drwxrwxr-x 2 overboom overboom 4096 5月 27 23:43 test_C++Sqlite/
drwxrwxr-x 6 overboom overboom 4096 5月 25 21:37 test_find/
-rwxrwxr-x 1 overboom overboom 141 9月 12 21:23 test.sh*
drwxrwxr-x 3 overboom overboom 4096 4月 10 17:36 xwp_linux/
overboom@overboom:~/Work$ cat out_file
total 52
drwxrwxr-x 11 overboom overboom 4096 9月 12 23:02 .
drwxr-xr-x 22 overboom overboom 4096 9月 12 22:47 ..
drwxr-xr-x 7 root root 4096 7月 4 18:39 beanCode
drwxrwxr-x 2 overboom overboom 4096 3月 27 23:45 c_code
drwxrwxr-x 3 overboom overboom 4096 8月 10 21:07 fdbus
drwxrwxr-x 3 overboom overboom 4096 8月 10 23:16 git_usage
drwxrwxr-x 4 overboom overboom 4096 6月 2 00:08 jsoncpp
drwxrwxr-x 2 overboom overboom 4096 8月 4 21:20 minixml
-rwxrwxr-x 1 overboom overboom 213 9月 12 22:45 position.sh
drwxrwxr-x 2 overboom overboom 4096 5月 27 23:43 test_C++Sqlite
drwxrwxr-x 6 overboom overboom 4096 5月 25 21:37 test_find
-rwxrwxr-x 1 overboom overboom 141 9月 12 21:23 test.sh
drwxrwxr-x 3 overboom overboom 4096 4月 10 17:36 xwp_linux
3.3 文件重定向
cmd > file 把标准输出重定向到新文件中
cmd >> file 追加
cmd > file 2>&1 标准出错也重定向到1所指向的file里
cmd >> file 2>&1
cmd < file1 > file2 输入输出都定向到文件里
cmd < &fd 把文件描述符fd作为标准输入
cmd > &fd 把文件描述符fd作为标准输出
cmd < &- 关闭标准输入
4.函数
和C语言类似,Shell中也有函数的概念,但是函数定义中没有返回值也没有参数列表。
Shell函数没有参数列表并不表示不能传参数,事实上,函数就像是迷你脚本,调用函数时可以传任意个参数,在函数内同样是用$0、$1、$2等变量来提取参数,函数中的位置参数相当于函数的局部变量,改变这些变量并不会影响函数外面的$0、$1、$2等变量。函数中可以用return命令返回,如果return后面跟一个数字则表示函数的Exit Status。
5. shell脚本调试方法
Shell提供了一些用于调试脚本的选项,如:
-n 读一遍脚本中的命令但不执行,用于检查脚本中的语法错误。
-v 一边执行脚本,一边将执行过的脚本命令打印到标准错误输出。
-x 提供跟踪执行信息,将执行的每一条命令和结果依次打印出来。
这些选项有三种常见的使用方法:
1.在命令行提供参数。如:
$ sh -x ./script.sh
2.在脚本开头提供参数。如:
#! /bin/sh -x
3.在脚本中用set命令启用或禁用参数。如:
#! /bin/sh
if [ -z "$1" ]; then
set -x
echo "ERROR: Insufficient Args."
exit 1
set +x
fi
set -x和set +x分别表示启用和禁用-x参数,这样可以只对脚本中的某一段进行跟踪调试。
以上是关于shell编程初步的主要内容,如果未能解决你的问题,请参考以下文章