Shell脚本编程入门

PHP是一个开源服务器端脚本语言,最初这三个字母代表的是“Personal Home
Page”,而现在则代表的是“PHP:Hypertext
Preprocessor”,它是个递归首字母缩写。它是一个跨平台脚本语言,深受C、C++和Java的影响。

一、什么是Shell脚本

澳门新浦京手机版 1

示例

看个例子吧:

#!/bin/sh
cd ~
mkdir shell_tut
cd shell_tut

for ((i=0; i<10; i++)); do
    touch test_$i.txt
done

在 Linux 命令行中运行 PHP 代码

示例解释
  • 第1行:指定脚本解释器,这里是用/bin/sh做解释器的
  • 第2行:切换到当前用户的home目录
  • 第3行:创建一个目录shell_tut
  • 第4行:切换到shell_tut目录
  • 第5行:循环条件,一共循环10次
  • 澳门新浦京手机版,第6行:创建一个test_0…9.txt文件
  • 第7行:循环体结束

mkdir, touch都是系统自带的程序,一般在/bin或者/usr/bin目录下。for, do,
done是sh脚本语言的关键字。

PHP的语法和C、Java以及带有一些PHP特性的Perl变成语言中的语法十分相似,它当下大约正被2.6亿个网站所使用,当前最新的稳定版本是PHP版本5.6.10。

shell和shell脚本的概念

shell是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。Ken
Thompson的sh是第一种Unix Shell,Windows
Explorer是一个典型的图形界面Shell。

shell脚本(shell
script),是一种为shell编写的脚本程序。业界所说的shell通常都是指shell脚本,但读者朋友要知道,shell和shell
script是两个不同的概念。由于习惯的原因,简洁起见,本文出现的“shell编程”都是指shell脚本编程,不是指开发shell自身(如Windows
Explorer扩展开发)。

PHP是HTML的嵌入脚本,它便于开发人员快速写出动态生成的页面。PHP主要用于服务器端(而Javascript则用于客户端)以通过HTTP生成动态网页,然而,当你知道可以在Linux终端中不需要网页浏览器来执行PHP时,你或许会大为惊讶。

二、环境

shell编程跟java、php编程一样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了。

本文将阐述PHP脚本语言的命令行方面。

操作系统

当前主流的操作系统都支持shell编程,本文档所述的shell编程是指Linux下的shell,讲的基本都是POSIX标准下的功能,所以,也适用于Unix及BSD(如Mac
OS)。

Linux

Linux默认安装就带了shell解释器。

Mac OS

Mac
OS不仅带了sh、bash这两个最基础的解释器,还内置了ksh、csh、zsh等不常用的解释器。

Windows上的模拟器

windows出厂时没有内置shell解释器,需要自行安装,为了同时能用grep, awk,
curl等工具,最好装一个cygwin或者mingw来模拟linux环境。

  • cygwin
  • mingw

1. 在安装完PHP和Apache2后,我们需要安装PHP命令行解释器。

脚本解释器

# apt-get install php5-cli          [Debian 及类似系统]
# yum install php-cli               [CentOS 及类似系统]
sh

即Bourne shell,POSIX(Portable Operating System
Interface)标准的shell解释器,它的二进制文件路径通常是/bin/sh,由Bell
Labs开发。

本文讲的是sh,如果你使用其它语言用作shell编程,请自行参考相应语言的文档。

接下来我们通常要做的是,在/var/www/html(这是 Apache2
在大多数发行版中的工作目录)这个位置创建一个内容为 <?php phpinfo();
?>,名为 infophp.php
的文件来测试(PHP是否安装正确),执行以下命令即可。

bash

Bash是Bourne shell的替代品,属GNU
Project,二进制文件路径通常是/bin/bash。业界通常混用bash、sh、和shell,比如你会经常在招聘运维工程师的文案中见到:熟悉Linux
Bash编程,精通Shell编程。

在CentOS里,/bin/sh是一个指向/bin/bash的符号链接:

[root@centosraw ~]# ls -l /bin/*sh
-rwxr-xr-x. 1 root root 903272 Feb 22 05:09 /bin/bash
-rwxr-xr-x. 1 root root 106216 Oct 17  2012 /bin/dash
lrwxrwxrwx. 1 root root      4 Mar 22 10:22 /bin/sh -> bash

但在Mac
OS上不是,/bin/sh和/bin/bash是两个不同的文件,尽管它们的大小只相差100字节左右:

iMac:~ wuxiao$ ls -l /bin/*sh
-r-xr-xr-x  1 root  wheel  1371648  6 Nov 16:52 /bin/bash
-rwxr-xr-x  2 root  wheel   772992  6 Nov 16:52 /bin/csh
-r-xr-xr-x  1 root  wheel  2180736  6 Nov 16:52 /bin/ksh
-r-xr-xr-x  1 root  wheel  1371712  6 Nov 16:52 /bin/sh
-rwxr-xr-x  2 root  wheel   772992  6 Nov 16:52 /bin/tcsh
-rwxr-xr-x  1 root  wheel  1103984  6 Nov 16:52 /bin/zsh
# echo '<?php phpinfo(); ?>' > /var/www/html/infophp.php
高级编程语言

理论上讲,只要一门语言提供了解释器(而不仅是编译器),这门语言就可以胜任脚本编程,常见的解释型语言都是可以用作脚本编程的,如:Perl、Tcl、Python、PHP、Ruby。Perl是最老牌的脚本编程语言了,Python这些年也成了一些linux发行版的预置解释器。

编译型语言,只要有解释器,也可以用作脚本编程,如C
shell是内置的(/bin/csh),Java有第三方解释器Jshell,Ada有收费的解释器AdaScript。

然后,将浏览器访问
,这将会在网络浏览器中打开该文件。

三、如何选择shell编程语言

澳门新浦京手机版 2

简单 vs 高级

如果你觉得自己熟悉的语言(如Java、C)写shell脚本实在太啰嗦,你只是想做一些备份文件、安装软件、下载数据之类的事情,学着使用sh,bash会是一个好主意。

shell只定义了一个非常简单的编程语言,所以,如果你的脚本程序复杂度较高,或者要操作的数据结构比较复杂,那么还是应该使用Python、Perl这样的脚本语言,或者是你本来就已经很擅长的高级语言。因为sh和bash在这方面很弱,比如说:

  • 它的函数只能返回字串,无法返回数组
  • 它不支持面向对象,你无法实现一些优雅的设计模式
  • 它是解释型的,一边解释一边执行,连PHP那种预编译都不是,如果你的脚本包含错误(例如调用了不存在的函数),只要没执行到这一行,就不会报错

检查PHP信息

环境兼容性

如果你的脚本是提供给别的用户使用,使用sh或者bash,你的脚本将具有最好的环境兼容性,perl很早就是linux标配了,python这些年也成了一些linux发行版的标配,至于mac
os,它默认安装了perl、python、ruby、php、java等主流编程语言。

不需要任何浏览器,在Linux终端中也可以获得相同的结果。在Linux命令行中执行/var/www/html/infophp.php,如:

四、第一个shell脚本

# php -f /var/www/html/infophp.php

1. 编写

打开文本编辑器,新建一个文件,扩展名为sh(sh代表shell),扩展名并不影响脚本执行,见名知意就好,如果你用php写shell
脚本,扩展名就用php好了。

输入一些代码,第一行一般是这样:

#!/bin/bash
#!/usr/bin/php

“#!”是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行。

澳门新浦京手机版 3

2.运行

运行Shell脚本有两种方法:

作为可执行程序

chmod +x test.sh
./test.sh

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

通过这种方式运行bash脚本,第一行一定要写对,好让系统查找到正确的解释器。

这里的”系统”,其实就是shell这个应用程序(想象一下Windows
Explorer),但我故意写成系统,是方便理解,既然这个系统就是指shell,那么一个使用/bin/sh作为解释器的脚本是不是可以省去第一行呢?是的。

作为解释器参数

这种运行方式是,直接运行解释器,其参数就是shell脚本的文件名,如:

/bin/sh test.sh
/bin/php test.php

这种方式运行的脚本,不需要在第一行指定解释器信息,写了也没用。

从命令行检查PHP信息

五、shell变量

Shell编程中,可以使用变量,这充分体现了他的灵活性。对Shell来讲,所有的变量的取值都是一个字符串。Shell脚本中主要有以下几种变量:

  • 系统变量
  • 环境变量
  • 用户变量

由于输出结果太大,我们可以通过管道将上述输出结果输送给 less
命令,这样就可以一次输出一屏了,命令如下:

1. 系统变量

以下是一些常用到的Shell系统变量以及其含义:

$#:获取命令行参数的个数
$0:获取当前的程序名
$*:获取所有命令行参数(以字符串的形式)
$@:获取所有命令行参数(以字符串数组的形式)
$n:获取命令行的第n个参数

# php -f /var/www/html/infophp.php | less
2. 环境变量

Shell环境变量是所有Shell程序都会接受的参数,Shell程序运行时,都会接受一组变量,这组变量就是环境变量,常用的Shell环境变量如下:

$PATH:决定了Shell将到哪个目录中寻找命令或程序(查看环境变量的配置)
$HOME:当前用户主目录的完全路径名
$HISTSIZE:历史纪录条数
$LOGNAME:当前用户的登录名
$SHELL:当前用户Shell类型
$HOSTNAME:指主机的名称
$UID:获取当前用户的 ID
$PWD:当前工作目录的绝对路径名

* 环境变量可以通过echo、unset来显示和设置
* env可以显示所有环境变量

澳门新浦京手机版 4

3. 用户变量

3.1 定义变量

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

your_name="qinjx"

注意,变量名和等号之间不能有空格,这可能和你熟悉的所有编程语言都不一样。

除了显式地直接赋值,还可以用语句给变量赋值,如:

for file in `ls /etc`
  • declare / typeset

declare或typeset是一样的功能,就是声明变量的类型。

declare [-aixr] variable
-a:将变量定义为数组类型
-i:将变量定义为整数类型
-x:将变量定义为环境变量
-r:将变量设置为readonly类型

3.2 使用变量

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

your_name="qinjx"
echo $your_name
echo ${your_name}

变量名外面的花括号是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,比如下面这种情况:

for skill in Ada Coffe Action Java; do
    echo "I am good at ${skill}Script"
done

如果不给skill变量加花括号,写成echo “I am good at
$skillScript”,解释器就会把$skillScript当成一个变量(其值为空),代码执行结果就不是我们期望的样子了。

推荐给所有变量加上花括号,这是个好的编程习惯。IntelliJ IDEA编写shell
script时,IDE就会提示加花括号。

3.3 重定义变量

已定义的变量,可以被重新定义,如:

your_name="qinjx"
echo $your_name

your_name="alibaba"
echo $your_name

这样写是合法的,但注意,第二次赋值的时候不能写$your_name=”alibaba”,使用变量的时候才加美元符。

3.4 变量键盘读取

  • read

read [-pt] variable
-p:后面可以接提示符
-t:后面可以接等待的秒数

例如:

read -p “Please keyin your name” -t 30 named

检查所有PHP信息

六、注释

以“#”开头的行就是注释,会被解释器忽略。

这里,‘-f‘选项解析并执行命令后跟随的文件。

多行注释

sh里没有多行注释,只能每一行加一个#号。就像这样:

##### 用户配置区 开始 #####
#
#
# 项目根目录,推荐将此脚本放在项目的根目录,这里就不用改了
# 应用名,确保和Xcode里Product下的target_name.app名字一致
#
##### 用户配置区 结束  #####

如果在开发过程中,遇到大段的代码需要临时注释起来,过一会儿又取消注释,怎么办呢?每一行加个#符号太费力了,可以把这一段要注释的代码用一对花括号括起来,定义成一个函数,没有地方调用这个函数,这块代码就不会执行,达到了和注释一样的效果。

2.
我们可以直接在Linux命令行使用phpinfo()这个十分有价值的调试工具而不需要从文件来调用,只需执行以下命令:

七、字符串

字符串是shell编程中最常用最有用的数据类型(除了数字和字符串,也没啥其它类型好用了,哈哈),字符串可以用单引号,也可以用双引号,也可以不用引号。单双引号的区别跟PHP类似。

# php -r 'phpinfo();'
单引号
str='this is a string'

单引号字符串的限制:

  • 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的
  • 单引号字串中不能出现单引号(对单引号使用转义符后也不行)

澳门新浦京手机版 5

双引号
your_name='qinjx'
str="Hello, I know your are "$your_name"! n"
  • 双引号里可以有变量
  • 双引号里可以出现转义字符

PHP调试工具

字符串操作
  1. 拼接字符串

your_name="qinjx"
greeting="hello, "$your_name" !"
greeting_1="hello, ${your_name} !"

echo $greeting $greeting_1
  1. 获取字符串长度

string="abcd"
echo ${#string} #输出:4
  1. 提取子字符串

string="alibaba is a great company"
echo ${string:1:4} #输出:liba
  1. 查找子字符串

string="alibaba is a great company"
echo `expr index "$string" is`#输出:3,这个语句的意思是:找出字母i在这名话中的位置,要在linux下运行,mac下会报错

这里,‘-r‘ 选项会让PHP代码在Linux终端中不带<和>标记直接执行。

八、流程控制语句

和Java、PHP等语言不一样,sh的流程控制不可为空,如:

<?php
if (isset($_GET["q"])) {
    search(q);
}
else {
    //do nothing
}

在sh/bash里可不能这么写,如果else分支没有语句执行,就不要写这个else。

还要注意,sh里的if [ $foo -eq 0
],这个方括号跟Java/PHP里if后面的圆括号大不相同,它是一个可执行程序(和ls,
grep一样),想不到吧?在CentOS上,它在/usr/bin目录下:

ll /usr/bin/[
-rwxr-xr-x. 1 root root 33408 6月  22 2012 /usr/bin/[

正因为方括号在这里是一个可执行程序,方括号后面必须加空格,不能写成if
[$foo -eq 0]

3. 以交互模式运行PHP并做一些数学运算。这里,‘-a‘
选项用于以交互模式运行PHP。

1. if else

if

if condition
then
    command1 
    command2
    ...
    commandN 
fi

写成一行(适用于终端命令提示符):

if `ps -ef | grep ssh`;  then echo hello; fi

末尾的fi就是if倒过来拼写,后面还会遇到类似的

if else

if condition
then
    command1 
    command2
    ...
    commandN
else
    command
fi

if else-if else

if condition1
then
    command1
elif condition2
    command2
else
    commandN
fi
# php -a

Interactive shell

php > echo 2+3;
5
php > echo 9-6;
3
php > echo 5*4;
20
php > echo 12/3;
4
php > echo 12/5;
2.4
php > echo 2+3-1;
4
php > echo 2+3-1*3;
2
php > exit
2. for while

for

在开篇的示例里演示过了:

for var in item1 item2 ... itemN
do
    command1
    command2
    ...
    commandN
done

写成一行:

for var in item1 item2 ... itemN; do command1; command2… done;

C风格的for

for (( EXP1; EXP2; EXP3 ))
do
    command1
    command2
    command3
done

while

while condition
do
    command
done

无限循环

while :
do
    command
done

或者

while true
do
    command
done

或者

for (( ; ; ))

until

until condition
do
    command
done

输入 ‘exit‘ 或者按下 ‘ctrl+c‘ 来关闭PHP交互模式。

3. case
case "${opt}" in
    "Install-Puppet-Server" )
        install_master $1
        exit
    ;;

    "Install-Puppet-Client" )
        install_client $1
        exit
    ;;

    "Config-Puppet-Server" )
        config_puppet_master
        exit
    ;;

    "Config-Puppet-Client" )
        config_puppet_client
        exit
    ;;

    "Exit" )
        exit
    ;;

    * ) echo "Bad option, please choose again"
esac

case的语法和C
family语言差别很大,它需要一个esac(就是case反过来)作为结束标记,每个case分支用右圆括号,用两个分号表示break

澳门新浦京手机版 6

九、重定向

  • 标准输入:代码为0,使用<<<
  • 标准输出:代码为1,使用>>>
  • 标准错误输出:代码为2,使用2>2>>
  • 如果想将正确与错误的数据同时写入同一个文件中,使用&>

输出:

可以将命令的输出内容保存至文件,若文件不存在,系统将会自动创建。
若使用的是>,原有的文件将会被覆盖;
若使用的是>>,将会添加到文件末尾。

输入:

将原本需要键盘输入的数据改由文件内容来替代。
<<当键盘输入指定内容时,输入就结束。

启用PHP交互模式

十、命令执行判断依据

当我们需要一次执行很多命令时,我们有一下几种方法:

  1. cmd ; cmd

可以一次执行多个命令,但是不考虑命令之间的相关性,也就是说前面的命令不能影响后面的命令是否执行。

  1. &&||

若一个命令执行的结果正确,在Linux下面会回传一个$?=0(命令回传码)的值;
我们可以通过逻辑运算符&&||来进行判断:

cmd1 && cmd2
若cmd1支持正确,则开始执行cmd2,否则不执行;

cmd1 || cmd2
若cmd1支持错误,则开始执行cmd2,否则不执行;

4.
你可以仅仅将PHP脚本作为shell脚本来运行。首先,创建在你当前工作目录中创建一个PHP样例脚本。

十一、管道命令

管道命令“ | ”能将前一个命令传来的正确信息作为输入传递给后一个命令。

常用的管道命令:

1. cut
将同一行里面的数据进行分解,用于分析一些数据或文字

2. grep
利用正则表达式分析一行数据

3. sort
可帮助我们进行排序

4. uniq
删除重复数据

5. wc
计算输出内容的相关信息

6. tee
同时将数据流送到文件和屏幕

7. tr
删除或替换一段信息中的文字

8. expand
将tab按键转换成空格键

9. split
将大文件切割为小文件

10.xargs
以空格符作为分割,产生某个命令的参数
# echo -e '#!/usr/bin/php/n<?php phpinfo(); ?>' > phpscript.php

十二、文件包含

可以使用source和.关键字,如:

source ./function.sh
. ./function.sh

在bash里,source和.是等效的,他们都是读入function.sh的内容并执行其内容(类似PHP里的include),为了更好的可移植性,推荐使用第二种写法。

包含一个文件和执行一个文件一样,也要写这个文件的路径,不能光写文件名,比如上述例子中:

. ./function.sh

不可以写作:

. function.sh

如果function.sh是用户传入的参数,如何获得它的绝对路径呢?方法是:

real_path=`readlink -f $1`#$1是用户输入的参数,如function.sh
. $real_path

注意,我们在该PHP脚本的第一行使用#!/usr/bin/php,就像在shell脚本中那样(/bin/bash)。第一行的#!/usr/bin/php告诉Linux命令行用
PHP 解释器来解析该脚本文件。

十三、函数

函数是存在内存里的一组代码的命名的元素。

函数的语法结构为:

function <function-name> {
    <code to execute>
}

我们使用位置参数$1来接收命令行里传递的参数,需要注意的是$1
用大括号来括起来。

shell
脚本是从上至下来执行的,如果在一个函数中调用了另一个函数,那么被调用的函数要定义在调用函数的前面。

当然,除了函数可以传递参数外,还可以有返回值。默认情况下,在执行完函数内的最后一行代码后,方法会返回一个状态的数字,你可以使用$?变量来查看函数执行的状态。如果返回值为0,表示方法正常退出,非0表示程序发生错误或其他非正常退出。

我们使用return关键字来返回一个整数。这里需要注意两点:

  • 函数一旦执行完就会返回状态代码。状态代码的范围为0到255。
  • 如果不想返回函数的状态代码,而是想返回一个字符串或是其他类型,可以使用
    echo 变量的方式来返回值。

其次,让该脚本可执行:

参考

鸟哥的Linux私房菜
Shell脚本编程30分钟入门

# chmod 755 phpscript.php

接着来运行它,

# ./phpscript.php

5.
你可以完全靠自己通过交互shell来创建简单函数,这你一定会被惊到了。下面是循序渐进的指南。

开启PHP交互模式。

# php -a

创建一个函数,将它命名为 addition。同时,声明两个变量 $a 和 $b。

php > function addition ($a, $b)

使用花括号来在其间为该函数定义规则。

php > {

定义规则。这里,该规则讲的是添加这两个变量。

php { echo $a + $b;

所有规则定义完毕,通过闭合花括号来封装规则。

php {}

测试函数,添加数字4和3,命令如下:

php > var_dump (addition(4,3));

样例输出

7NULL

你可以运行以下代码来执行该函数,你可以测试不同的值,你想来多少次都行。将里头的
a 和 b 替换成你自己的值。

php > var_dump (addition(a,b));

php > var_dump (addition(9,3.3));

样例输出

12.3NULL

澳门新浦京手机版 7

创建PHP函数

你可以一直运行该函数,直至退出交互模式(ctrl+z)。同时,你也应该注意到了,上面输出结果中返回的数据类型为
NULL。这个问题可以通过要求 php 交互 shell用 return 代替 echo
返回结果来修复。

只需要在上面的函数的中 ‘echo‘ 声明用 ‘return‘ 来替换

替换

php { echo $a + $b;

php { return $a + $b;

剩下的东西和原理仍然一样。

这里是一个样例,在该样例的输出结果中返回了正确的数据类型。

澳门新浦京手机版 8

PHP函数

永远都记住,用户定义的函数不会从一个shell会话保留到下一个shell会话,因此,一旦你退出交互shell,它就会丢失了。

希望你喜欢此次教程。保持连线,你会获得更多此类文章。保持关注,保持健康。请在下面的评论中为我们提供有价值的反馈。点赞并分享,帮助我们扩散。

发表评论

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