⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 shell编程.txt

📁 shell编程指南请详细阅读
💻 TXT
📖 第 1 页 / 共 5 页
字号:
第2章	带着一个Sha-Bang出发(Sha-Bang指的是#!)
==============================================
在一个最简单的例子中,一个shell脚本其实就是将一堆系统命令列在一个文件中.它的最基本的
用处就是,在你每次输入这些特定顺序的命令时可以少敲一些字.

Example 2-1 清除:清除/var/log下的log文件
################################Start Script#######################################
1 # Cleanup
2 # 当然要使用root身份来运行这个脚本
3 
4 cd /var/log
5 cat /dev/null > messages
6 cat /dev/null > wtmp
7 echo "Logs cleaned up."
################################End Script#########################################
这根本就没什么稀奇的, 只不过是命令的堆积, 来让从console或者xterm中一个一个的输入命
令更方便一些.好处就是把所有命令都放在一个脚本中,不用每次都敲它们.这样的话,对于特定
的应用来说,这个脚本就很容易被修改或定制.

Example 2-2 清除:一个改良的清除脚本
################################Start Script#######################################
 1 #!/bin/bash
 2 # 一个Bash脚本的正确的开头部分.
 3 
 4 # Cleanup, 版本 2
 5 
 6 # 当然要使用root身份来运行.
 7 # 在此处插入代码,来打印错误消息,并且在不是root身份的时候退出.
 8 
 9 LOG_DIR=/var/log
10 # 如果使用变量,当然比把代码写死的好.
11 cd $LOG_DIR
12 
13 cat /dev/null > messages
14 cat /dev/null > wtmp
15 
16 
17 echo "Logs cleaned up."
18 
19 exit # 这个命令是一种正确并且合适的退出脚本的方法.
################################End Script#########################################

现在,让我们看一下一个真正意义的脚本.而且我们可以走得更远...
Example 2-3. cleanup:一个增强的和广义的删除logfile的脚本
################################Start Script#######################################
 1 #!/bin/bash
 2 # 清除, 版本 3
 3 
 4 #  Warning:
 5 #  -------
 6 #  这个脚本有好多特征,这些特征是在后边章节进行解释的,大概是进行到本书的一半的
 7 #  时候,
 8 #  你就会觉得它没有什么神秘的了.
 9 #
10 
11 
12 
13 LOG_DIR=/var/log
14 ROOT_UID=0     # $UID为0的时候,用户才具有根用户的权限
15 LINES=50       # 默认的保存行数
16 E_XCD=66       # 不能修改目录?
17 E_NOTROOT=67   # 非根用户将以error退出
18 
19 
20 # 当然要使用根用户来运行
21 if [ "$UID" -ne "$ROOT_UID" ]
22 then
23   echo "Must be root to run this script."
24   exit $E_NOTROOT
25 fi  
26 
27 if [ -n "$1" ]
28 # 测试是否有命令行参数(非空).
29 then
30   lines=$1
31 else  
32   lines=$LINES # 默认,如果不在命令行中指定
33 fi  
34 
35 
36 #  Stephane Chazelas 建议使用下边
37 #+ 的更好方法来检测命令行参数.
38 #+ 但对于这章来说还是有点超前.
39 #
40 #    E_WRONGARGS=65  # 非数值参数(错误的参数格式)
41 #
42 #    case "$1" in
43 #    ""      ) lines=50;;
44 #    *[!0-9]*) echo "Usage: `basename $0` file-to-cleanup"; exit $E_WRONGARGS;;
45 #    *       ) lines=$1;;
46 #    esac
47 #
48 #* 直到"Loops"的章节才会对上边的内容进行详细的描述.
49 
50 
51 cd $LOG_DIR
52 
53 if [ `pwd` != "$LOG_DIR" ]  # 或者	if[ "$PWD" != "$LOG_DIR" ]
54                             # 不在 /var/log中?
55 then
56   echo "Can't change to $LOG_DIR."
57   exit $E_XCD
58 fi  # 在处理log file之前,再确认一遍当前目录是否正确.
59 
60 # 更有效率的做法是
61 #
62 # cd /var/log || {
63 #   echo "Cannot change to necessary directory." >&2
64 #   exit $E_XCD;
65 # }
66 
67 
68 
69 
70 tail -$lines messages > mesg.temp # 保存log file消息的最后部分.
71 mv mesg.temp messages             # 变为新的log目录.
72 
73 
74 # cat /dev/null > messages
75 #* 不再需要了,使用上边的方法更安全.
76 
77 cat /dev/null > wtmp  #  ': > wtmp' 和 '> wtmp'具有相同的作用
78 echo "Logs cleaned up."
79 
80 exit 0
81 #  退出之前返回0,返回0表示成功.
82 #
################################End Script#########################################

因为你可能希望将系统log全部消灭,这个版本留下了log消息最后的部分.你将不断地找到新
的方法来完善这个脚本,并提高效率.

要注意,在每个脚本的开头都使用"#!",这意味着告诉你的系统这个文件的执行需要指定一个解
释器.#!实际上是一个2字节[1]的魔法数字,这是指定一个文件类型的特殊标记, 换句话说, 在
这种情况下,指的就是一个可执行的脚本(键入man magic来获得关于这个迷人话题的更多详细
信息).在#!之后接着是一个路径名.这个路径名指定了一个解释脚本中命令的程序,这个程序可
以是shell,程序语言或者是任意一个通用程序.这个指定的程序从头开始解释并且执行脚本中
的命令(从#!行下边的一行开始),忽略注释.[2]
如:
1 #!/bin/sh
2 #!/bin/bash
3 #!/usr/bin/perl
4 #!/usr/bin/tcl
5 #!/bin/sed -f
6 #!/usr/awk -f

上边每一个脚本头的行都指定了一个不同的命令解释器,如果是/bin/sh,那么就是默认shell
(在Linux系统中默认是Bash).[3]使用#!/bin/sh,在大多数商业发行的UNIX上,默认是Bourne
shell,这将让你的脚本可以正常的运行在非Linux机器上,虽然这将会牺牲Bash一些独特的特征.
脚本将与POSIX[4] 的sh标准相一致.

注意: #! 后边给出的路径名必须是正确的,否则将会出现一个错误消息,通常是
"Command not found",这将是你运行这个脚本时所得到的唯一结果.

当然"#!"也可以被忽略,不过这样你的脚本文件就只能是一些命令的集合,不能够使用shell内建
的指令了,如果不能使用变量的话,当然这也就失去了脚本编程的意义了.

	注意:这个例子鼓励你使用模块化的方式来编写脚本,平时也要注意收集一些零碎的代码,
		这些零碎的代码可能用在你将来编写的脚本中.这样你就可以通过这些代码片段来构
		造一个较大的工程用例. 以下边脚本作为序,来测试脚本被调用的参数是否正确.
################################Start Script#######################################
 1 E_WRONG_ARGS=65
 2 script_parameters="-a -h -m -z"
 3 #                  -a = all, -h = help, 等等.
 4 
 5 if [ $# -ne $Number_of_expected_args ]
 6 then
 7   echo "Usage: `basename $0` $script_parameters"
 8   # `basename $0`是这个脚本的文件名
 9   exit $E_WRONG_ARGS
10 fi
################################End Script#########################################
大多数情况下,你需要编写一个脚本来执行一个特定的任务,在本章中第一个脚本就是一个这样
的例子, 然后你会修改它来完成一个不同的,但比较相似的任务.用变量来代替写死的常量,就是
一个好方法,将重复的代码放到一个函数中,也是一种好习惯.


2.1 调用一个脚本
----------------
编写完脚本之后,你可以使用sh scriptname,[5]或者bash scriptname来调用它.
(不推荐使用sh <scriptname,因为这禁用了脚本从stdin中读数据的功能.)
更方便的方法是让脚本本身就具有可执行权限,通过chmod命令可以修改.

比如:
    chmod 555 scriptname (允许任何人都具有 可读和执行权限) [6]  
或:
	chmod +rx scriptname (允许任何人都具有 可读和执行权限)
	chmod u+rx scriptname (只给脚本的所有者 可读和执行权限)

既然脚本已经具有了可执行权限,现在你可以使用./scriptname.[7]来测试它了.如果这个脚本
以一个"#!"行开头,那么脚本将会调用合适的命令解释器来运行.

最后一步,在脚本被测试和debug之后,你可能想把它移动到/usr/local/bin(当然是以root身份)
,来让你的脚本对所有用户都有用.这样用户就可以直接敲脚本名字来运行了.

注意事项:
[1]		那些具有UNIX味道的脚本(基于4.2BSD)需要一个4字节的魔法数字,在#!后边需要一个
		空格#! /bin/sh.
[2]		脚本中的#!行的最重要的任务就是命令解释器(sh或者bash).因为这行是以#开始的,
		当命令解释器执行这个脚本的时候,会把它作为一个注释行.当然,在这之前,这行语句
		已经完成了它的任务,就是调用命令解释器.

		如果在脚本的里边还有一个#!行,那么bash将把它认为是一个一般的注释行.
		 1 #!/bin/bash
		 2 
		 3 echo "Part 1 of script."
		 4 a=1
		 5 
		 6 #!/bin/bash
		 7 # 这将不会开始一个新脚本.
		 8 
		 9 echo "Part 2 of script."
		10 echo $a  # Value of $a stays at 1.
[3]		这里可以玩一些小技巧.
		 1 #!/bin/rm
		 2 # 自删除脚本.
		 3 
		 4 # 当你运行这个脚本时,基本上什么都不会发生...除非这个文件消失不见.
		 5 
		 6 WHATEVER=65
		 7 
		 8 echo "This line will never print (betcha!)."
		 9 
		10 exit $WHATEVER  # 没关系,脚本是不会在这退出的.
		当然,你还可以试试在一个README文件的开头加上#!/bin/more,并让它具有执行权限.
		结果将是文档自动列出自己的内容.(一个使用cat命令的here document可能是一个
		更好的选则,--见Example 17-3).
[4]		可移植的操作系统接口,标准化类UNIX操作系统的一种尝试.POSIX规范可以在
		http://www.opengroup.org/onlinepubs/007904975/toc.htm中查阅.
[5]		小心:使用sh scriptname来调用脚本的时候将会关闭一些Bash特定的扩展,脚本可能
		因此而调用失败.
[6]		脚本需要读和执行权限,因为shell需要读这个脚本.
[7]		为什么不直接使用scriptname来调用脚本?如果你当前的目录下($PWD)正好有你想要
		执行的脚本,为什么它运行不了呢?失败的原因是,出于安全考虑,当前目录并没有被
		加在用户的$PATH变量中.因此,在当前目录下调用脚本必须使用./scriptname这种
		形式.


2.2 初步的练习
--------------
1. 系统管理员经常会为了自动化一些常用的任务而编写脚本.举出几个这种有用的脚本的实例.
2. 编写一个脚本,显示时间和日期,列出所有的登录用户,显示系统的更新时间.然后这个脚本
   将会把这些内容保存到一个log file中.


第二部分	基本
++++++++++++++++

第3章	特殊字符
================

#		注释,行首以#开头为注释(#!是个例外).

		1 # This line is a comment.

		注释也可以存在于本行命令的后边.

		1 echo "A comment will follow." # 注释在这里
		2 #                            ^ 注意#前边的空白

		注释也可以在本行空白的后边.

		1 	# A tab precedes this comment.

		注意:命令是不能跟在同一行上注释的后边的,没有办法,在同一行上,注释的后边想
		要再使用命令,只能另起一行.
		当然,在echo命令中被转义的#是不能作为注释的. 
		同样的,#也可以出现在特定的参数替换结构中或者是数字常量表达式中.

		1 echo "The # here does not begin a comment."
		2 echo 'The # here does not begin a comment.'
		3 echo The \# here does not begin a comment.
		4 echo The # 这里开始一个注释
		5 
		6 echo ${PATH#*:}       # 参数替换,不是一个注释
		7 echo $(( 2#101011 ))  # 数制转换,不是一个注释
		8 
		9 # Thanks, S.C.

		标准的引用和转义字符("'\)可以用来转义#

;		命令分隔符,可以用来在一行中来写多个命令.

		1 echo hello; echo there
		2 
		3 
		4 if [ -x "$filename" ]; then    # 注意:"if"和"then"需要分隔
		5                                # 为啥?
		6   echo "File $filename exists."; cp $filename $filename.bak
		7 else
		8   echo "File $filename not found."; touch $filename
		9 fi; echo "File test complete."

		有时候需要转义

;;		终止"case"选项.

		1 case "$variable" in
		2 abc)  echo "\$variable = abc" ;;
		3 xyz)  echo "\$variable = xyz" ;;
		4 esac

.		.命令等价于source命令(见Example 11-20).这是一个bash的内建命令.

.		.作为文件名的一部分.如果作为文件名的前缀的话,那么这个文件将成为隐藏文件.
		将不被ls命令列出.

		bash$ touch .hidden-file
		bash$ ls -l	      
		total 10
		-rw-r--r--    1 bozo      4034 Jul 18 22:04 data1.addressbook
		-rw-r--r--    1 bozo      4602 May 25 13:58 data1.addressbook.bak
		-rw-r--r--    1 bozo       877 Dec 17  2000 employment.addressbook
		
		
		bash$ ls -al	      
		total 14
		drwxrwxr-x    2 bozo  bozo      1024 Aug 29 20:54 ./
		drwx------   52 bozo  bozo      3072 Aug 29 20:51 ../
		-rw-r--r--    1 bozo  bozo      4034 Jul 18 22:04 data1.addressbook
		-rw-r--r--    1 bozo  bozo      4602 May 25 13:58 data1.addressbook.bak
		-rw-r--r--    1 bozo  bozo       877 Dec 17  2000 employment.addressbook
		-rw-rw-r--    1 bozo  bozo         0 Aug 29 20:54 .hidden-file

		.命令如果作为目录名的一部分的话,那么.表达的是当前目录.".."表示上一级目录.

		bash$ pwd
		/home/bozo/projects

		bash$ cd .
		bash$ pwd
		/home/bozo/projects

		bash$ cd ..
		bash$ pwd
		/home/bozo/

		.命令经常作为一个文件移动命令的目的地.

		bash$ cp /home/bozo/current_work/junk/* .

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -