#1 Finding Programs in the PATH
FileName:FindingProgram
#!/bin/sh # inpath - Verifies that a specified program is either valid as is, # or that it can be found in the PATH directory list. in_path() { # Given a command and the PATH, try to find the command. Returns # 0 if found and executable, 1 if not. Note that this temporarily modifies # the IFS (input field separator) but restores it upon completion. cmd=$1 path=$2 retval=1 oldIFS=$IFS IFS=":" for directory in $path do if [ -x $directory/$cmd ] ; then retval=0 # if we're here, we found $cmd in $directory fi done IFS=$oldIFS return $retval } checkForCmdInPath() { var=$1 # The variable slicing notation in the following conditional # needs some explanation: ${var#expr} returns everything after # the match for 'expr' in the variable value (if any), and # ${var%expr} returns everything that doesn't match (in this # case, just the very first character. You can also do this in # Bash with ${var:0:1}, and you could use cut too: cut -c1. if [ "$var" != "" ] ; then if [ "${var%${var#?}}" = "/" ] ; then if [ ! -x $var ] ; then return 1 fi elif ! in_path $var $PATH ; then return 2 fi fi } if [ $# -ne 1 ] ; then echo "Usage: $0 command" >&2 ; exit 1 fi checkForCmdInPath "$1" case $? in 0 ) echo "$1 found in PATH" ;; 1 ) echo "$1 not found or not executable" ;; 2 ) echo "$1 not found in PATH" ;; esac exit 0
HowToRun:1、 chmod u+x FindingProgram >>>>./FindingProgram xxx ========All Scripts as follow are Running in This Way.
2、显式制定 BASH 去执行
其中,当前目录不是当前用户可执行文件的默认目录,而将当前目录“.”设为默认目录是一个不安全的设置。
The Results:
$ ./FindingProgram echo
echo found in PATH
$ ./FindingProgram MrEcho
MrEcho not found in PATH
$ ./FindingProgram /usr/bin/MrEcho
/usr/bin/MrEcho not found or not executable
解析代码
#! 是说明文件的类型的,类似于 Windows 系统下用不同文件后缀来表示不同文件类型的意思(但不相同)。Linux 系统根据 "#!" 及该字串后面的信息确定该文件的类型,可以通过 "man magic"命令 及/usr/share/magic 文件来了解这方面的更多内容。
"#!" 及后面的 "/bin/bash" 就表明该文件是一个 BASH 程序,需要由 /bin 目录下的 bash 程序来解释执行。BASH 这个程序一般是存放在 /bin 目录下,如果自己的 Linux 系统比较特别,bash 也有可能被存放在 /sbin 、/usr/local/bin 、/usr/bin 、/usr/sbin 或 /usr/local/sbin 这样的目录下;如果还找不到,你可以用 "locate bash" "find / -name bash 2> /dev/null" 或 "whereis bash" 这三个命令找出 bash 所在的位置;如果仍然找不到,那你可能需要自己动手安装一个 BASH 软件包了。
变量介绍
先来从整体上把握一下 BASH 中变量的用法,然后再去分析 BASH 中变量使用与 C 语言中的不同。BASH 中的变量都是不能含有保留字,不能含有 "-" 等保留字符,也不能含有空格。
简单变量
在 BASH 中变量定义是不需要的,没有 "int i" 这样的定义过程。如果想用一个变量,只要他没有在前面被定义过,就直接可以用,当然你使用该变量的第一条语句应该是对他赋初值了,如果你不赋初值也没关 系,只不过该变量是空( 注意:是 NULL,不是 0 )。不给变量赋初值虽然语法上不反对,但不是一个好的编程习惯。看看下面的例子:
首先用 vi 编辑下面这个文件 hello2:
#!/bin/bash # give the initialize value to STR STR="Hello World" echo $STR在上面这个程序中我们需要 注意下面几点:
BASH 中的语句结尾不需要分号(";");
除了在变量赋值和在FOR循环语句头中,BASH 中的变量使用必须在变量前加"$"符号,可以将上面程序中第三行改为 "echo STR" 再试试,看看会出什么结果。==>output: STR
由于 BASH 程序是在一个新的进程中运行的,所以该程序中的变量定义和赋值不会改变其他进程或原始 Shell 中同名变量的值,也不会影响他们的运行。
但引号括起来的变量将不被 BASH 解释为变量,如 '$STR' ,而被看成为纯粹的字符串。而且更为标准的变量引用方式是 ${STR} 这样的,$STR 自不过是对 ${STR} 的一种简化。在复杂情况下(即有可能产生歧义的地方)最好用带 {} 的表示方式。
BASH 中的变量既然不需要定义,也就没有类型一说,一个变量即可以被定义为一个字符串,也可以被再定义为整数。如果对该变量进行整数运算,他就被解释为整数;如果对他进行字符串操作,他就被看作为一个字符串。请看下面的例子:
#!/bin/bash x=1999 let "x = $x + 1" echo $x x="olympic'"$x echo $x关于整数变量计算,有如下几种:" + - * / % ",他们的意思和字面意思相同。整数运算一般通过 let 和 expr 这两个指令来实现,如对变量 x 加 1 可以写作:let "x = $x + 1" 或者 x=`expr $x + 1`
对应的操作
|
整数操作
|
字符串操作
|
相同
|
-eq
|
=
|
不同
|
-ne
|
!=
|
大于
|
-gt
|
>
|
小于
|
-lt
|
<
|
大于或等于
|
-ge
|
|
小于或等于
|
-le
|
|
为空
|
-z
|
|
不为空
|
-n
|
比如:
比较字符串 a 和 b 是否相等就写作:if [ $a = $b ]
判断字符串 a 是否为空就写作: if [ -z $a ]
判断整数变量 a 是否大于 b 就写作:if [ $a -gt $b ]
在字符串比较时尽量不要使用 -n ,而用 ! -z 来代替。(其中符号 "!" 表示求反操作)
BASH 中的变量除了用于对 整数 和 字符串 进行操作以外,另一个作用是作为文件变量。BASH 是 Linux 操作系统的 Shell,因此系统的文件必然是 BASH 需要操作的重要对象,如 if [ -x /root ] 可以用于判断 /root 目录是否可以被当前用户进入。下表列出了 BASH 中用于判断文件属性的操作符:
运算符
|
含义( 满足下面要求时返回 TRUE ) |
-e file
|
文件 file 已经存在{exist} |
-f file
|
文件 file 是普通文件 |
-s file
|
文件 file 大小不为零{size} |
-d file
|
文件 file 是一个目录{directory} |
-r file
|
文件 file 对当前用户可以读取{read} |
-w file
|
文件 file 对当前用户可以写入{write} |
-x file
|
文件 file 对当前用户可以执行{execute} |
-g file
|
文件 file 的 GID 标志被设置 |
-u file
|
文件 file 的 UID 标志被设置 |
-O file
|
文件 file 是属于当前用户的 |
-G file
|
文件 file 的组 ID 和当前用户相同 |
file1 -nt file2
|
文件 file1 比 file2 更新 |
file1 -ot file2
|
文件 file1 比 file2 更老 |
注意:上表中的 file 及 file1、file2 都是指某个文件或目录的路径。
关于局部变量
在 BASH 程序中如果一个变量被使用了,那么直到该程序的结尾,该变量都一直有效。为了使得某个变量存在于一个局部程序块中,就引入了局部变量的概念。BASH 中,在变量首次被赋初值时加上 local 关键字就可以声明一个局部变量,如下面这个例子:
#!/bin/bash HELLO=Hello function hello { local HELLO=World echo $HELLO } echo $HELLO hello echo $HELLO
该程序的执行结果是:
Hello
World
Hello
这个执行结果表明全局变量 $HELLO 的值在执行函数 hello 时并没有被改变。也就是说局部变量 $HELLO 的影响只存在于函数那个程序块中。
BASH 中的变量与 C 语言中变量的区别
不熟悉 BASH 编程,但是非常熟悉 C 语言的程序员总结一下在 BASH 环境中使用变量需要注意的问题。
1,BASH 中的变量在引用时都需要在变量前加上 "$" 符号( 第一次赋值及在For循环的头部不用加 "$"符号 );
2,BASH 中没有浮点运算,因此也就没有浮点类型的变量可用;
3,BASH 中的整形变量的比较符号与 C 语言中完全不同,而且整形变量的算术运算也需要经过 let 或 expr 语句来处理;
if [ expression ] then statments fi或者
if [ expression ] then statments else statments fi或者
if [ expression ] then statments else if [ expression ] then statments else statments fi或者
if [ expression ] then statments elif [ expression ] then statments else statments fi
下面这个例子说明了如何使用 if 条件判断语句:
#!/bin/bash if [ $1 -gt 90 ] then echo "Good, $1" elif [ $1 -gt 70 ] then echo "OK, $1" else echo "Bad, $1" fi exit 0for
for $var in
do
statments
done
其中
$var 是循环控制变量, 是 $var 需要遍历的一个集合,do/done 对包含了循环体,
如果do 和 for 被写在同一行,必须在 do 前面加上 ";"。如:
for $var in ; do 。
下面是一个运用 for 进行循环的例子:
#!/bin/bash for day in Sun Mon Tue Wed Thu Fri Sat do echo $day done # 如果列表被包含在一对双引号中,则被认为是一个元素 for day in "Sun Mon Tue Wed Thu Fri Sat" do echo $day done exit 0注意上面的例子中, 在 for 所在那行的变量 day 是没有加 "$" 符号的,而在循环体内,echo 所在行变量 $day 是必须加上 "$" 符号的。另外 如果写成 for day 而没有后面的 in 部分,则 day 将取遍命令行的所有参数。 如这个程序:
#!/bin/bash for param do echo $param done exit 0上面这 个程序将列出所有命令行参数。for 循环结构的循环体被包含在 do/done 对中,这也是后面的 while、until 循环所具有的特点。
while [ condition ] do statments doneuntil
until [ condition is TRUE ] do statments donecase
case "$var" in condition1 ) statments1;; condition2 ) statments2;; ... * ) default statments;; esac下面这个程序是运用 case 结构进行分支执行的例子:
#!/bin/bash echo "Hit a key, then hit return." read Keypress case "$Keypress" in [a-z] ) echo "Lowercase letter";; [A-Z] ) echo "Uppercase letter";; [0-9] ) echo "Digit";; * ) echo "Punctuation, whitespace, or other";; esac exit 0"read Keypress" 一句中的 read 语句表示从键盘上读取输入。
function my_funcname { code block }或者
my_funcname() { code block }上面的第二种写法更接近于 C 语言中的写法。 BASH 中要求函数的定义必须在函数使用之前,这是和 C 语言用头文件说明函数方法的不同。
#!/bin/bash square() { let "res = $1 * $1" return $res } square $1 result=$? echo $result exit 0其他高级问题
select var in do statments use $var done上面的语法结构在执行后,BASH 会将 中的所有项加上数字列在屏幕上等待用户选择,在用户作出选择后,变量 $var 中就包含了那个被选中的字符串,然后就可以对该变量进行需要的操作了。可以从下面的例子中更直观的来理解这个功能:
#!/bin/bash OPTIONS="Hello Quit" select opt in $OPTIONS; do if [ "$opt" = "Quit" ]; then echo done exit elif [ "$opt" = "Hello" ]; then echo Hello World else clear echo bad option fi done exit 0
#!/bin/bash echo Please enter your name read NAME echo "Hi! $NAME !" exit 0上面这个脚本读取用户的输入,并回显在屏幕上。
#!/bin/bash passwd="aka@tsinghua" ftp -n localhost <<FTPFTP user anonymous $passwd binary bye FTPFTP exit 0
while : do operation-1 operation-2 ... operation-n done
#!/bin/bash : ${HOSTNAME?} {USER?} {MAIL?} echo $HOSTNAME echo $USER echo $MAIL exit 0export 命令用于将系统变量输出到外层的 Shell 中 。