Man -- 指令帮助 一起从这里开始
+程序必须以下面的行开始(必须方在文件的第一行):
#!/bin/sh
符号#!用来告诉系统它后面的参数是用来执行该文件的程序。在这个例子中我们使用/bin/sh来执行程序。
当编辑好脚本时,如果要执行该脚本,还必须使其可执行。
要使脚本可执行:编译 chmod +x filename 这样才能用./filename 来运行
+以#开头的句子表示注释,直到这一行的结束
+在shell编程中,所有的变量都由字符串组成,并且您不需要对变量进行声明 a="hello world"; echo $a
可以使用花括号来告诉shell我们要打印的是num变量
num=2
echo "this is the ${num}nd"
这将打印: this is the 2nd
+在shell脚本中可以使用三类命令:
1)Unix 命令 2) 概念: 管道, 重定向和 backtick
1)Unix 命令:
虽然在shell脚本中可以使用任意的unix命令,但是还是由一些相对更常用的命令。这些命令通常是用来
进行文件和文字操作的。
常用命令语法及功能
echo "some text": 将文字内容打印在屏幕上
ls: 文件列表
wc –l filewc -w filewc -c file: 计算文件行数计算文件中的单词数计算文件中的字符数
cp sourcefile destfile: 文件拷贝
mv oldname newname : 重命名文件或移动文件
rm file: 删除文件
grep 'pattern' file: 在文件内搜索字符串比如:grep 'searchstring' file.txt
cut -b colnum file: 指定欲显示的文件内容范围,并将它们输出到标准输出设备比如:输出
每行第5个到第9个字符cut -b5-9 file.txt千万不要和cat命令混淆,
这是两个完全不同的命令
cat file.txt: 输出文件内容到标准输出设备(屏幕)上
file somefile: 得到文件类型
read var: 提示用户输入,并将输入赋值给变量
sort file.txt: 对file.txt文件中的行进行排序
uniq: 删除文本文件中出现的行列比如: sort file.txt | uniq
expr: 进行数学运算Example: add 2 and 3expr 2 "+" 3
find: 搜索文件比如:根据文件名搜索find . -name filename -print
tee: 将数据输出到标准输出设备(屏幕) 和文件比如:somecommand | tee outfile
basename file: 返回不包含路径的文件名比如: basename /bin/tux将返回 tux
dirname file: 返回文件所在路径比如:dirname /bin/tux将返回 /bin
head file: 打印文本文件开头几行
tail file : 打印文本文件末尾几行
sed: Sed是一个基本的查找替换程序。可以从标准输入(比如命令管道)读入文本,并将
结果输出到标准输出(屏幕)。该命令采用正则表达式(见参考)进行搜索。
不要和shell中的通配符相混淆。比如:将linuxfocus 替换为
LinuxFocus :cat text.file | sed 's/linuxfocus/LinuxFocus/' > newtext.file
awk: awk 用来从文本文件中提取字段。缺省地,字段分割符是空格,可以使用-F指定其他分割符。
cat file.txt | awk -F, '{print $1 "," $3 }'这里我们使用,作为字段分割符,同时打印
第一个和第三个字段。如果该文件内容如下: Adam Bor, 34, IndiaKerry Miller, 22, USA
命令输出结果为:Adam Bor, IndiaKerry Miller, USA
2) 概念: 管道, 重定向和 backtick:
+管道 (|) 将一个命令的输出作为另外一个命令的输入。 grep "hello" file.txt | wc -l 在file.txt中搜索包含有”hello”的行
并计算其行数。
+重定向:将命令的结果输出到文件,而不是标准输出(屏幕)。
> 写入文件并覆盖旧文件
>> 加到文件的尾部,保留旧文件内容。
+反短斜线
使用反短斜线可以将一个命令的输出作为另外一个命令的一个命令行参数。
命令:
find . -mtime -1 -type f -print
用来查找过去24小时(-mtime –2则表示过去48小时)内修改过的文件。如果您
想将所有查找到的文件打一个包,则可以使用以下脚本:tar -zcvf lastmod.tar.gz `find . -mtime -1 -type f -print`
+3) 流程控制
1.if
"if" 表达式 如果条件为真则执行then后面的部分:
if ....; then
....
elif ....; then
....
else
....
fi
大多数情况下,可以使用测试命令来对条件进行测试。比如可以比较字符串、判断文件
是否存在及是否可读等等…
通常用" [ ] "来表示条件测试。注意这里的空格很重要。要确保方括号的空格。
[ -f "somefile" ] :判断是否是一个文件
[ -x "/bin/ls" ] :判断/bin/ls是否存在并有可执行权限
[ -n "$var" ] :判断$var变量是否有值
[ "$a" = "$b" ] :判断$a和$b是否相等
执行man test可以查看所有测试表达式可以比较和判断的类型。
直接执行以下脚本:
#!/bin/sh
if [ "$SHELL" = "/bin/bash" ]; then
echo "your login shell is the bash (bourne again shell)"
else
echo "your login shell is not bash but $SHELL"
fi
变量$SHELL包含了登录shell的名称,我们和/bin/bash进行了比较。
2.case
case :表达式可以用来匹配一个给定的字符串,而不是数字。
case ... in
...) do something here ;;
esac
让我们看一个例子。 file命令可以辨别出一个给定文件的文件类型,比如:
file lf.gz
这将返回:
lf.gz: gzip compressed data, deflated, original filename,
last modified: Mon Aug 27 23:09:18 2001, os: Unix
我们利用这一点写了一个叫做smartzip的脚本,该脚本可以自动解压bzip2, gzip 和zip 类型的压缩文件:
#!/bin/sh
ftype=`file "$1"`
case "$ftype" in
"$1: Zip archive"*)
unzip "$1" ;;
"$1: gzip compressed"*)
gunzip "$1" ;;
"$1: bzip2 compressed"*)
bunzip2 "$1" ;;
*) echo "File $1 can not be uncompressed with smartzip";;
esac
您可能注意到我们在这里使用了一个特殊的变量$1。该变量包含了传递给该程序的第一个参数值。
也就是说,当我们运行:
smartzip articles.zip
$1 就是字符串 articles.zip
3. selsect
select 表达式是一种bash的扩展应用,尤其擅长于交互式使用。用户可以从一组不同的值中进行选择。
select var in ... ; do
break
done
.... now $var can be used ....
下面是一个例子:
#!/bin/sh
echo "What is your favourite OS?"
select var in "Linux" "Gnu Hurd" "Free BSD" "Other"; do
break
done
echo "You have selected $var"
下面是该脚本运行的结果:
What is your favourite OS?
1) Linux
2) Gnu Hurd
3) Free BSD
4) Other
#? 1
You have selected Linux
4.loop
loop表达式:
while ...; do
....
done
while-loop 将运行直到表达式测试为真。will run while the expression that we test for is true.
关键字"break" 用来跳出循环。而关键字”continue”用来不执行余下的部分而直接跳到下一个循环
for-loop表达式查看一个字符串列表 (字符串用空格分隔) 然后将其赋给一个变量:
for var in ....; do
....
done
在下面的例子中,将分别打印ABC到屏幕上:
#!/bin/sh
for var in A B C ; do
echo "var is $var"
done
下面是一个更为有用的脚本showrpm,其功能是打印一些RPM包的统计信息:
#!/bin/sh
# list a content summary of a number of RPM packages
# USAGE: showrpm rpmfile1 rpmfile2 ...
# EXAMPLE: showrpm /cdrom/RedHat/RPMS/*.rpm
for rpmpackage in $*; do
if [ -r "$rpmpackage" ];then
echo "=============== $rpmpackage =============="
rpm -qi -p $rpmpackage
else
echo "ERROR: cannot read file $rpmpackage"
fi
done
这里出现了第二个特殊的变量$*,该变量包含了所有输入的命令行参数值。
如果您运行showrpm openssh.rpm w3m.rpm webgrep.rpm
此时 $* 包含了 3 个字符串,即openssh.rpm, w3m.rpm and webgrep.rpm.
+Unix 是可以在许多种机器上运行的操作系统,但人们又如何使用这些机器呢?他们是通过哑终端来连接到这些机器,也就是用键盘
、显示器及足够的 electronics (电子元件)组成的机器与中央计算机(central computer)相连。在这些终端上,用户可以敲字符
(teletypy),这就是字符串'tty'表示终端设备文件,和'getty'命令的名称来历。
+为了在终端中运行程序,需要 shell 。shell 是操作系统的一部分,用来与用户打交道,并且可以用来协调各个命令。
+通过光标和功能键(Home、End 等键),您可以浏览并编辑命令行,如果您需要,还可以用键盘的快捷方式来完成一般的编辑:
l <CTRL k>:删除从光标到行尾的部分
l <CTRL u>:删除从光标到行首的部分
l <ALT d>:删除从光标到当前单词结尾的部分
l <CTRL w>:删除从光标到当前单词开头的部分
l <CTRL a>:将光标移到行首
l <CTRL e>:将光标移到行尾
l <ALT a>:将光标移到当前单词头部
l <ALT e>:将光标移到当前单词尾部
l <CTRL y>:插入最近删除的单词
l <!$>:重复前一个命令最后的参数。
例如:您用命令 mkdir peter/pan/documents/tinkerbell 新建了一个目录,现在您向用命令'cd'进入该目录,您可以用 cd !$,
shell 将把前一个命令'mkdir'的参数添加到现在的'cd'后面。
+'~'就是您的 home 目录的简写形式。我们假设您在其他目录,想把一个名为'sometext'的文件复制到您 home 目录下的 'docs'子目录中。除了输入:
cp sometext /home/myusername/docs
您还可以用简写:
cp sometext ~/docs
+command1 && command2
只有当 command1 正确运行完毕后,才执行 command2 。
例如:
ls -a bogusdir && du -hs
将返回 ls: bogusdir: No such file or directory ,而'du'则根本没有运行(这是因为您没有'bogusdir'目录)。如果您将符号
换成了';','du'将被执行。
+当您在终端里运行一个命令或开启一个程序时,终端要等到命令或程序运行完毕后,才能再被使用。在 Unix 中,我们称这样的命
令或程序在前台(foreground)运行。如果您想在终端下运行另一个命令,则需要再打开一个新的终端。
但这里还有一个更优雅的办法,称为任务调度(jobbing)或后台(backgrounding)。当您运用任务的调度或将命令置于后台,终端就立
即解放了,这样一来,终端立即就可以接受新的输入。为实现这样的目的,您只需在命令后面添加一个 & :
gqview &
告诉 shell 将图片查看器'GQview'放到后台去执行(即当成 job 来运行)。
命令 jobs 将告诉您,在这个终端窗口中,运行着哪些命令与程序:
jobs
[1]+ Running gqview &
当您要关闭终端窗口时,这一点就很重要,因为关闭终端将导致所有在其中运行的任务都将被中止,在此例中,如果您关闭了终端,
由这个终端开启的 GQview 程序也将被关闭。
但如何将前台运行的一个程序放到后台去?没问题:
gqview
<CTRL z>
[2]+ Stopped gqview
bg
[2]+ gqview &
组合键 将挂起终端中正在运行的程序,然后您就可以用 bg 命令将其放到后台去执行。
请注意,在后台运行图形应用程序有时候是有用处的,这样可以在终端下显示这个程序的出错信息,虽然这对您可能没有直接的帮助
,当如果碰到了麻烦,向别人询问时,这些出错提示就有用武之地了。
一些图形程序,很可能还处在测试期(Beta),尽管在后台执行,也会在终端中输出一些信息。如果您对此不满,可以用下面命令:
command &>/dev/null &
这不仅将程序送到后台执行,还将其输出发到'/dev/null'文件。'/dev/null'是系统的"碎纸机" (shredder),所有送到那里的信息
都将消失殆尽。
+命令替换(Command substitution)是一项很实用的功能。我们假设,您想看看 XFree86 文档中的 'README.mouse'文件,但您不知
道这个文件的位置。但您是位机灵的用户,已经听说了'locate'命令,也安装了'slocate'包,您就可以用:
locate README.mouse
发现那个文件在'/usr/X11R6/lib/X11/doc'。现在您就可以在终端里用'less'或在文件管理器中进入那个目录然后读取文件。而命令
替换可以给您带来一些便捷:
less $(locate README.mouse)
一步到位。命令'locate README.mouse'的输出(= /usr/X11R6/lib/X11/doc/README.mouse)作为'less'的参数,然后就可以显示文件
内容了。
这种机制的语法是:
command1 $(command2)
除了'$( )',您还可以用后引号(backquote):
command1 `command2`
这样虽然可以减少输入,但可读性差,而且很容易就和没有替换功能的一般单引号混淆。我更欣赏前一种方法,但这最终起决于您。
这里有另外一个例子。我们假设,您打算结束一个名为'rob'的程序。您先得用命令'pidof'找出相应的进程号(Process ID),然后以
这个 PID 为参数,运行'kill'命令,这样就可以结束'rob'程序。除了用:
pidof rob
567
kill 567
您还可以试试:
kill `pidof rob`
第四篇:文件名匹配/输出重定向
一、文件名匹配
文件名匹配使得您不必一一写出名称,就可以指定多个文件。您将用到一些特殊的字符,称为通配符(wildcards)。
假设您想用'rm'命令删除目录下所有以字符串'.bak'结尾的文件。除了在'rm'后跟上所有文件名作为参数,您还可以用通配符'*':
rm *.bak
'*'可匹配一个或多个字符。在本例中,您告诉 shell 将命令'rm'的参数扩展到"所有以'*.bak'结尾的文件",shell 就将扩展后的
参数告诉'rm'命令。
您将看到,shell 在命令执行前,就将读取并解释命令行。正是因为这个,您才可以将通配符用于 shell 命令的参数中。
让我们更进一步地来认识通配符'*'。假定您有个目录,其中含文件'124.bak'、'346.bak'及'583.bak'。您想只保留文件'583.bak'
,可以用:
rm *4*.bak
shell 就将'*4*.bak'扩展成"所有含'4'并以'.bak'结尾的字符串"。
如果您想保留文件'345.bak',而删除'124.bak'和'583.bak'。这看起来有些难度,因为被删文件的名称除了后缀其他都不同。但幸
运的是,您可以用不含有来指定文件:
rm *[!6].bak
这将被读为:除了以'6.bak'结尾的文件,删除其他所有以'.bak'结尾的文件。您必须将取反号(negation sign)与取反字符(这里是
6)放到括号中,不然的话,shell 会将惊叹号(exclamation mark)解释成历史记录替换的开始(the beginning of a history
substitution)。取反号在本篇介绍的所有匹配模式中都有效。
请注意:通配符'*'与取反号连用,很容易产生问题。猜猜
rm *[!6]*.bak
表示什么?这个命令将删除所有文件,甚至包括名称中包含'6'的文件。如果您将通配符'*'放到了取反号前面和后面,实际上取反号
将失效,因为 shell 将其解释为"所有名称中任何位置都不含该字符的文件"。在我们的例子里,只有文件'666.bak'不符合该模式。
第二个通配符是问号(question mark):'?'。在匹配时,一个问号只能代表一个字符。
问号通配符能够有效地避免上面提到的'取反号陷阱'(negation trap):
rm *[!4]?.*
将扩展成"所有除了点号前倒数第二个字符为'4'的文件",也就是只保留文件'346.bak'。
ls [13]*
将列出所有以字符'1'或'3'开头的文件
匹配的范围:
ls *[3-8]?.*
将列出所有点号前倒数第二个字符落在'3'到'8'范围的文件。
您可以通过反斜线(back slash)来引用特殊字符,比如 ! 、$ 、? 或空格:
ls /!*
!56.bak
或者用(单)引号:
ls '!'*
!56.bak
请注意,要看清楚引号应该放在什么位置。命令 ls '!*' 将查找名为'!*'的文件,这是由于通配符也在引号间,所以只能依照字面
来解释。
+Unix 的理念是汇集许多小程序,每个东东都有特殊的专长。复杂的任务不是由大型软件完成,而是运用 shell 的机制,组合许多
小程序共同完成。重定向就在其中发挥着重要的作用。
1、在多个命令间重定向
这要通过管道(pipe),由管道符号|来标识。语法是:
command1 | command2 | command3 等等
2、重定向至文件
有时,您希望将命令的输出结果保存到文件中,或以文件内容作为命令的参数。这可以通过'>'和'<'来实现。
command > file
将当前目录的内容保存到'dirlist'文件。
command < file
将 file 内容作为 command 的输入
sort < dirlist > sdirlist
将文件'dirlist'的内容送到命令'sort',然后再将排序后的结果送到文件'sdirlist'。当然,您也可以一步到位:
ls | sort > sdirlist
一种特殊的方式是'command 2> file'。这将 command 执行的出错信息送到 file 中。这个您到时候会需要……
另一种操作符是'>>',这将输出添加到已存在的文件中:
echo "string" >> file
将 string 加到文件 file 中。这是不打开文件而完成编辑的好办法!
但是,'<'和'>'操作符都有一个重要的限制:
command < file1 > file1
将删除 file1 的内容,而
command < file1 >> file1
却可以很好地工作,将加工过的 file1 内容加回到文件中。
第五篇:bash 配置文件/提示符/改变 $PATH
一、bash 配置文件
在您的 home 目录下,运行
ls .bash*
您将看到这些文件:
l .bash_history :记录了您以前输入的命令,
l .bash_logout :当您退出 shell 时,要执行的命令,
l .bash_profile :当您登入 shell 时,要执行的命令,
l .bashrc :每次打开新的 shell 时,要执行的命令。
1、命令的别名
+例如,我用下面的命令来上传 MUO 中的文件:
rsync -e ssh -z -t -r -vv --progress /home/tom/web/muo/rsmuo/docs muo:/www/mandrakeuser/docs
显然,如果每次都要逐一输入,那我早晚会变成木头。因此我在'~/.bashrc'中定义了别名:
alias upmuo='rsync -e ssh -z -t -r -vv --progress /home/tom/web/muo/rsmuo/docs muo:/www/mandrakeuser/docs'
现在,我只要输入 upmuo 就可以完成上传任务了。
定义别名的语法是:
alias shortcut='command'
+命令中有空格的话 ,就需要用引号(如在命令与可选项间就有空格)。请注意,您可以用单引号或双引号,但他们是有区别的。
单引号将剥夺其中的所有字符的特殊含义,而双引号中的'$'(参数替换)和'`'(命令替换)是例外。这意味着,如果您想在别名中
应用变量或命令的替换,就得用双引号。看一下上面的例子,我在'.bashrc'中定义了一个称为 MUOHOME 的变量:
export MUOHOME=$HOME/web/muo/rsmuo/docs
要在上面的别名中用上这个变量,我就必须用双引号:
alias upmuo="rsync -e ssh -z -t -r -vv --progress $MUOHOME muo:/www/mandrakeuser/docs"
否则,别名将查找一个名为'$MUOHOME'的目录或文件。
您可以用'alias'在命令行快速地创建别名,或将命令放到各自的'~/.bashrc',或放到系统级的'/etc/profile.d/alias.sh'中(而
在 Mandrake Linux 8 以前的版本里,用的是'/etc/bashrc')。要删除一个别名,只要输入:unalias alias 。运行 alias 将列出
您系统中所有定义的别名。
+目录的别名也可以是可移动的介质:alias dlm='/mnt/cdrom/RedHat/RPMS/' 。
提示:将有相似功能的别名以相同字母开头,比如将所有目录的别名以'd'作开头,这样有助于记忆。
2、Shell 函数
+通过 shell 函数,您可以做很多 aliases 无法完成的事情。下面就是一个例子:
function apros() { apropos $1 | egrep -v '(3|/(n/)'; }
+函数允许您在函数内部任何位置,使用运行时的参数。而别名,则只允许在命令行尾放一个参数(比如前面的别名'rpmq')。
'$1'就是位置参数(positional parameter),表示函数第一个参数的位置标识符。依此类推,还有'$2'等。
function apros() { apropos $1 | egrep -v "/($2"; }
+shell 函数的处理类似于别名:将其放到您的'.bashrc'文件,这样就能永久生效了。