脚本语言

一直很困惑什么是脚本,python是不是脚本,脚本怎么定义的?我觉得最主要的就是以下两点.

  1. 脚本语言不需要编译,可以直接用,由解释器来负责解释.
  2. 脚本语言一般都是以文本形式存在,类似于一种命令.

其实理解批处理就可以理解shell了,早期的程序员是通过shell来进行文件的批处理,而程序员想要对文件进行控制就不能等文件一个个运行完再输入吧,所以创造了shell脚本语言,程序员只需要写入命令到一个文件里,然后shell一行行读取,就能实现批处理了.

以大部分都是整理自http://see.xidian.edu.cn/cpp/view/6994.html

1 Bash

Bash 是 GNU shell,兼容 sh 以及其他 shell 里的许多有用的特性。用户可以选择在终端里运行哪种解析器.

运行如下命令可以查看机器里有哪种解析器:

cat /etc/shells

自从遇见zsh后,我就转入了zsh门下,建议大家尝试一下,它还有一个很好的配置插件oh-my-zsh.自认为比bash好上不少.

2 编写脚本

2.1 执行脚本的方法:

  1. 将文件夹放入PATH中export PATH="$PATH:~/scripts",改变文件权限chmod u+x script1.sh,直接运行script1.sh
  2. 如果没有加入PATH,那么这样也可以运行./script_name.sh
  3. 也可以这样,自己定义用哪个shell执行bash script_name.sh(一般不会用这个把)
  4. source script_name.sh,这里的source.是一样的效果,不过source不需要文件的执行权限.前三种方法都是在子shell里运行的命令,当命令结束的时候,子shell会退出,所有状态会清空.而这种方法是在自己的shell里运行的,也就是说脚本里设定的变量再本shell下依然可以实用(其他的调用不了哦)

注意,执行一个文件一定要写成./test.sh,而不是test.sh。运行其它二进制的程序也一样,直接写test.sh,linux系统会去PATH里寻找有没有叫test.sh的,而只有/bin, /sbin, /usr/bin,/usr/sbin等在PATH里,你的当前目录通常不在PATH里,所以写成test.sh是会找不到命令的,要用./test.sh告诉系统说,就在当前目录找。

2.2 脚本基础

2.2.1用哪个脚本来运行

一般的脚本程序都会有下面这一行:

#!/bin/bash

就是告诉这个脚本用哪种shell来运行,防止用其他shell运行出错.

注意:前面不能留空行,必须写在第一行

2.2.2加入注释

范例:

#!/bin/bash 
# This script clears the terminal, displays a greeting and gives information 
# about currently connected users. The two example variables are set and displayed. 
clear # clear terminal window 
echo "The script starts now." 
echo "Hi, $USER!" # dollar sign is used to get content of variable 
echo 
echo "I will now fetch you a list of connected users:" 
echo 
w # show who is logged on and 
echo # what they are doing 
echo "I'm setting two variables now."
COLOUR="black" # set a local shell variable 
VALUE="9" # set a local shell variable 
echo "This is a string: $COLOUR" # display content of variable 
echo "And this is a number: $VALUE" # display content of variable 
echo 
echo "I'm giving you back your prompt now." 
echo 

2.3 调试脚本

2.3.1 调试整个脚本
illy:~/scripts> bash −x script1.sh 
+ clear 
+ echo 'The script starts now.' 
The script starts now. 
+ echo 'Hi, willy!' 
Hi, willy! 
+ echo 
+ echo 'I will now fetch you a list of connected users:' 
I will now fetch you a list of connected users: 
+ echo 
+ w 
4:50pm up 18 days, 6:49, 4 users, load average: 0.58, 0.62, 0.40 
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT 
root tty2 − Sat 2pm 5:36m 0.24s 0.05s −bash 
willy :0 − Sat 2pm ? 0.00s ? − 
willy pts/3 − Sat 2pm 43:13 36.82s 36.82s BitchX willy ir 
willy pts/2 − Sat 2pm 43:13 0.13s 0.06s /usr/bin/screen 
+ echo 
+ echo 'I'\''m setting two variables now.' 
I'm setting two variables now. 
+ COLOUR=black 
+ VALUE=9 
+ echo 'This is a string: ' 
This is a string: 
+ echo 'And this is a number: ' 
And this is a number: 
+ echo 
+ echo 'I'\''m giving you back your prompt now.' 
I'm giving you back your prompt now. 
+ echo 

以前真没用过,这样可以一行一行的观察脚本的运行了

2.3.2 调试部分脚本

在文件上下加上set -x

set −x # activate debugging from here 
w 
set +x # stop debugging from here 

然后输出

willy: ~/scripts> script1.sh 
The script starts now. 
Hi, willy! 
I will now fetch you a list of connected users: 
+ w 
5:00pm up 18 days, 7:00, 4 users, load average: 0.79, 0.39, 0.33 
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT 
root tty2 ? Sat 2pm 5:47m 0.24s 0.05s ?bash 
willy :0 ? Sat 2pm ? 0.00s ? ? 
willy pts/3 ? Sat 2pm 54:02 36.88s 36.88s BitchX willyke 
willy pts/2 ? Sat 2pm 54:02 0.13s 0.06s /usr/bin/screen 
+ set +x 
I'm setting two variables now. 
This is a string: 
And this is a number: 
I'm giving you back your prompt now. 

奇怪的是我在shell上没有显示,不知道是为什么?有知道的请告知

调试的详细参数如下:

bash -选择项 shell程序文件名

几个常用的选择项是:

  1. set −f set −o noglob Disable file name generation using metacharacters (globbing). (文件)
  2. set −v set −o verbose Prints shell input lines as they are read. (输出的同时输出命令)
  3. set −x set −o xtrace Print command traces before executing command. (加入所有的调试信息)

你可以把这些选项加入到脚本头部,这样:

#!/bin/bash -xv 

当然最后,本人最长用的是echo~~

3 Bash环境

3.1 shell初始化配置

跨系统配置

linux文件下主要的bash配置文件:

  1. /etc/inputrc,可以配置命令行响铃风格的跨系统的行读取初始化文件。
  2. /etc/profile.d 目录,包含了配置特别程序的跨系统行为的文件。
  3. /etc/profile:此文件为系统的每个用户设置环境信息,当用户第一次登录时,该文件被执行,并从/etc/profile.d目录的配置文件中搜集shell的设置,
  4. /etc/bashrc:为每一个运行bash shell的用户执行此文件,当bash shell被打开时,该文件被读取。
  5. ~/.bash_profile:每个用户都可使用该文件输入专用于自己使用的shell信息,当用户登录时,该文件仅仅执行一次!默认情况下,他设置一些环境变量,执行用户的.bashrc文件。
  6. ~/.bash_login:这个文件包含了只有在你登陆进系统的才执行的特殊的设置。
  7. ~/.profile在没有~/.bash_profile 和~/.bash_login 的情况下,~/.profile 就被读取。他能保存一些可以被别的 shell 访问的配置。注意其他的 shell 可能不能识别 Bash 的语法。
  8. ~/.bashrc:如今,更加普遍的是使用一个非登陆 shell,比如使用 X 终端窗口登陆进图形模式的时候。打开一个这样的窗口之后,用户不需要提供用户名和密码;无需认证。此时 Bash 会搜索~/.bashrc,所以也指向登陆时读取得文件,同时也意味着你不需要在多个文件中输入相同的设置.

3.2 变量

3.2.1 变量的类型

shell 变量约定俗成地用大写表示

  • 全局变量:全局变量或者环境变量存在于所有的 shell 里面。envprintenv命令能够通常用于显示环变量。

  • 本地变量:本地变量只存在于当前 shell。使用内建的不带选项的set命令将显示所有变量的列表(包括环 境变量)和函数。输出会根据当前的设置排列而且以可以重用的方式显示。

3.2.2 变量基本操作
定义变量

定义变量时,变量名不加美元符号($),如:

variableName="value"

注意,变量名和等号之间不能有空格,这可能和你熟悉的所有编程语言都不一样。同时,变量名的命名须遵循如下规则:

  1. 首个字符必须为字母(a-z,A-Z)。
  2. 中间不能有空格,可以使用下划线(_)。
  3. 不能使用标点符号。
  4. 不能使用bash里的关键字(可用help命令查看保留关键字)。

变量定义举例:

myUrl="http://see.xidian.edu.cn/cpp/linux/"
myNum=100
使用变量

使用一个定义过的变量,只要在变量名前面加美元符号($)即可,如:

your_name="mozhiyan"
echo $your_name
echo ${your_name}

推荐给所有变量加上花括号,这是个好的编程习惯。

只读变量

使用readonly命令可以将变量定义为只读变量,只读变量的值不能被改变。

#!/bin/bash
myUrl="http://see.xidian.edu.cn/cpp/shell/"
readonly myUrl
myUrl="http://see.xidian.edu.cn/cpp/danpianji/"

运行脚本,结果如下:

/bin/sh: NAME: This variable is read only.
删除变量

使用unset 命令可以删除变量。语法:

unset variable_name

变量被删除后不能再次使用;unset 命令不能删除只读变量。

举个例子:

#!/bin/sh
myUrl="http://see.xidian.edu.cn/cpp/u/xitong/"
unset myUrl
echo $myUrl

上面的脚本没有任何输出。

3.2.3 特殊变量

特殊变量列表

|变量| 含义| |:--||:---| |$0 |当前脚本的文件名| |$n |传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是$2。| |$# |传递给脚本或函数的参数个数。| |$* |传递给脚本或函数的所有参数。| |$@| 传递给脚本或函数的所有参数。被双引号(" ")包含时,与 $* 稍有不同,下面将会讲到。| |$? |上个命令的退出状态,或函数的返回值。| |$$ |当前Shell进程ID。对于 Shell 脚本,就是这些脚本所在的进程ID。|

$* 和 $@ 的区别

$* 和 $@ 都表示传递给函数或脚本的所有参数,不被双引号(" ")包含时,都以"$1" "$2" … "$n" 的形式输出所有参数。

但是当它们被双引号(" ")包含时,"$*" 会将所有的参数作为一个整体,以"$1 $2 … $n"的形式输出所有参数;"$@" 会将各个参数分开,以"$1" "$2" … "$n" 的形式输出所有参数。

3.2.4 导出变量

在Bash Shell中变量都是局部的,它们只在创建它们的子Shell中有意义。使用export后,变量被设置为全局变量,这时可以被其它子Shell所识别 。

export VARNAME="value"

被export后的变量,可以成为环境变量.

3.2.5 变量替换
#!/bin/bash
a=10
echo -e "Value of a is $a \n"

运行结果:

Value of a is 10

这里 -e 表示对转义字符进行替换。如果不使用 -e 选项,将会原样输出:

Value of a is 10\n

下面的转义字符都可以用在 echo 中:

转义字符 含义
\ 反斜杠
\a 警报,响铃
\b 退格(删除键)
\f 换页(FF),将当前位置移到下页开头
\n 换行
\r 回车
\t 水平制表符(tab键)
\v 垂直制表符

可以使用 echo 命令的 -E 选项禁止转义,默认也是不转义的;使用 -n 选项可以禁止插入换行符。

命令替换

命令替换是指Shell可以先执行命令,将输出结果暂时保存,在适当的地方输出。

命令替换的语法:

`command`

注意是反引号,不是单引号,这个键位于 Esc 键下方。

下面的例子中,将命令执行结果保存在变量中:

#!/bin/bash
DATE=`date`
echo "Date is $DATE"
USERS=`who | wc -l`
echo "Logged in user are $USERS"
UP=`date ; uptime`
echo "Uptime is $UP"

运行结果:

Date is Thu Jul  2 03:59:57 MST 2009
Logged in user are 1
Uptime is Thu Jul  2 03:59:57 MST 2009
03:59:57 up 20 days, 14:03,  1 user,  load avg: 0.13, 0.07, 0.15
变量替换

变量替换可以根据变量的状态(是否为空、是否定义等)来改变它的值

可以使用的变量替换形式:

形式 说明
${var} 变量本来的值
${var:-word} 如果变量 var 为空或已被删除(unset),那么返回 word,但不改变 var 的值。
${var:=word} 如果变量 var 为空或已被删除(unset),那么返回 word,并将 var 的值设置为 word。
${var:?message} 如果变量 var 为空或已被删除(unset),那么将消息 message 送到标准错误输出,可以用来检测变量 var 是否可以被正常赋值。若此替换出现在Shell脚本中,那么脚本将停止运行。
${var:+word} 如果变量 var 被定义,那么返回 word,但不改变 var 的值。