昨天在往github上面push东西的时候,突然感觉我真是太蠢了,一个学计算机的,居然没有想到把三个命令集成在一个shell脚本里面。通过传入俩个参数,一个文件名,一个关于的递交的信息,这样不就一条命令就好了,还省了很多的事。但是准备写的时候,发现不怎么会使用shell编程,所以查阅了一些资料,决定写一篇关于shell编程的文章吧。这样,即使以后我忘记了,也可以方便查阅。最后,这篇文章是为了那些不会shell,或者不这么熟悉shell的同学,方便以后批处理文件,或者其他的事情。
介绍shell脚本
简单的说shell就是一个包含若干行Shell或者Linux命令的文件。对于一次编写,多次使用的大量命令,就可以使用单独的文件保存下来,以便日后使用。通常shell脚本以.sh
为后缀。在编写shell时,第一行一定要指明系统需要哪种shell解释用户的shell程序,如:#!/bin/sh
(Bourne Shell),#!/bin/bash
(Bourne Again Shell),#!/bin/csh
(C Shell),#!/bin/ksh
(K Shell)等等。
不同的Shell语言的语法有所不同,所以不能交换使用。每种Shell都有其特色之处,基本上,掌握其中任何一种 就足够了。在本文中,我们关注的重点是Bash,也就是Bourne Again Shell,由于易用和免费,Bash在日常工作中被广泛使用;同时,Bash也是大多数Linux系统默认的Shell。在一般情况下,人们并不区分 Bourne Shell和Bourne Again Shell,所以,在下面的文字中,我们可以看到#!/bin/sh
,它同样也可以改为#!/bin/bash
。下面的run.sh则指明使用bash执行。
#!bin/bash
ls -l
通常,shell脚本会以#!/bin/sh
作为默认的shell程序。执行shell的方式有两种:第一种是通过sh命令执行shell脚本,第二种是为shell脚本加上可执行权限并执行,例如执行当前目录下的run.sh脚本,命令如下:
1.通过sh命令执行shell脚本
sh run.sh
2.为shell脚本直接加上可执行权限并执行
chmod +x run.sh
./run.sh
chmod [who] operator [permission] filename
who的含义是:
u 文件属主权限。
g 同组用户权限。
o 其他用户权限。
a 所有用户(文件属主、同组用户及其他用户)。
operator的含义:
+ 增加权限。
- 取消权限。
= 设定权限。
permission的含义:
r 读权限。
w 写权限。
x 执行权限。
s 文件属主和组s e t - I D。
l 给文件加锁,使其他用户无法访问。
文 件 属 主 | 同 组 用 户 | 其 他 用 户 |
---|---|---|
r w x | r w x | r w x |
4 + 2 + 1 | 4 + 2 + 1 | 4 + 2 + 1 |
shell 使用
参数传递
$xxx
表示包括$0在内的命令行参数的个数。在Shell中,脚本名称本身是$0,剩下的依次是$0、$1、$2…、${10}、${11},等等。$*表示整个参数列表,不包括$0,也就是说不包括文件名的参数列表。
例:显示文件的内容123 456.txt
#!bin/bash
cat "$1"
有人可能会问,为什么要加"
,因为不加的话,执行指令时会解析成cat 123 456.txt
而不是cat 123\ 456.txt
,所以如果参数中有空格,就加上"
吧。
#!/bin/sh
#print hello world in the console window
a = "world"
echo "hello, $a" #输出 :hello world
echo "hello, $as" #希望输出:hello worlds
echo "Hello, $as"
就不会输出“hello, worlds”,而是输出“hello, ”。这是因为Shell把$as当成一个变量,而$as未被赋值,其值为空。正确的方法是:
echo "Hi, ${a}s"
基本控制语句
# if语句和其他编程语言相似,都是流程控制语句
if …; then
…
elif …; then
…
else
…
fi
# 在循环中,也可以使用类似C语言中的break和continue语句中断当前的循环操作。
for var in …; do
…
done
常用条件测试
[ -f "$file" ] 判断$file是否是一个文件
[ $a -lt 3 ] 判断$a的值是否小于3,同样-gt和-le分别表示大于或小于等于
[ -x "$file" ] 判断$file是否存在且有可执行权限,同样-r测试文件可读性
[ -n "$a" ] 判断变量$a是否有值,测试空串用-z
[ "$a" = "$b" ] 判断$a和$b的取值是否相等
[ cond1 -a cond2 ] 判断cond1和cond2是否同时成立,-o表示cond1和cond2有一成立
截取文件名信息
#:表示从左边算起第一个
%:表示从右边算起第一个
##:表示从左边算起最后一个
%%:表示从右边算起最后一个
basename 和 dirname
例如:
1、${var##*/}
该命令的作用是去掉变量var从左边算起的最后一个'/'字符及其左边的内容,返回从左边算起的最后一个'/'(不含该字符)的右边的内容。
#!bin/bash
var = /dir1/dir2/file.txt
echo ${var##*/}
# echo 输出到屏幕
# 输出:file.txt
2、${var%%.*}
该命令的使用是去掉变量var从右边算起的最后一个'.'字符及其右边的内容,返回从右边算起的最后一个'.'(不含该字符)的左边的内容。
#!bin/bash
var = /dir1/dir2/file.txt
echo ${var%%.*}
# 输出:/dir1/dir2/file
basename
该命令的作用是从路径中提取出文件名,使用方法为basename NAME
dirname
该命令的作用是从路径中提取出目录名,使用方法为 dirname NAME
这俩条命令不仅能提取出普通文件所的目录,它能提取出任何文件所在的目录,例如目录所在的目录。
#!bin/bash
var = /dir1/dir2/file.txt
echo basename $var
# 输出:file.txt
echo dirname $var
#输出:/dir1/dir2
获取某目录下所有文件夹的名称
#!/bin/bash
for dir in $(ls .)
do
[ -d $dir ] && echo $dir
done
注释,管道,重定向
1.shell脚本和其它编程语言一样,也拥有注释。注释方法为在注释行前加#号。
#!/bin/sh
#Filename: comment.sh
2.管道的作用是在一个命令的标准输出和另一个命令的标准输入之间建立一个通道。例如下面命令就是将ps -aux的标准输出传递给grep作为输入。
#!/bin/sh
ps -aux | grep httpd
3.输入重定向使用小于号“<”可以实现。输出重定向有两种方式,一种是直接输出,使用一个大于号“>”实现;另一种是以附加的方式输出,使用两个大于号“>>”实现。前者会覆盖原始的输出内容,而后者会添加到文件最后。
#!/bin/sh
cat < dir.txt # cat命令重定向到dir.txt文件
ls > dir.txt # ls命令重定向到dir.txt
ls >> dir.txt # ls命令以附加的方式重定向到dir.txt