您的位置:首页 > 运维架构 > Shell

Linux学习笔记之<Shell编程初入门>

2015-10-09 15:14 891 查看
薄雾浓云愁永昼,瑞脑消金兽。

佳节又重阳,玉枕纱橱,半夜凉初透

东篱把酒黄昏后,有暗香盈袖。

莫道不消魂,帘卷西风,人比黄花瘦。

本文的参考文档主要出自《Linux程序设计》第四版第二章。

可以看做是更符合国人思路的精简版。

本文不会很长,建议全篇阅读。

什么是Shell

管道和重定向
重定向输出

重定向输入

管道

作为程序设计语言的shell

shell的语法
变量

环境变量

条件

控制结构

函数

命令

什么是Shell

shell是人和linux操作系统进行交互的工具。本质上也是一个跑在linux上的程序罢了。除此之外,它还可以执行脚本文件,从文件而不是人这里获取指令。

管道和重定向

重定向输出

一个简单的例子

ls -l > `lsout`.txt


默认情况下,上面这个命令会覆盖lsout.txt

若想在文件上追加

ls -l >> lsout.txt


更多的内容:其实一个程序的输出不止一个。比如还有标准错误输出。(也许你之前没有接触到过,但是这点也很重要)

kill -HUP 1234 >killout.txt 2>killerr.txt


kill如果给一个已经结束的进程发送HUP信号,那么将会报错。

>killout.txt
表示将标准输出重定向到killout.txt这个文件。

2>killerr.txt
表示将标准错误输出定向到killerr.txt这个文件。

2代表的是标准错误输出。

如果将两者都输出到同一个文件,那么可以这样写

kill -HUP 1234 >killout.txt 2>&1


&1
的含义是标准输出的指向。

我们也可以丢弃掉输出的信息:

kill -1 1234 >/dev/null 2>&1


重定向输入

例如:

#more自身也可以直接读取文件
more < killout.txt


管道

有些时候使用管道明显更方便:

ps|sort|more


注意不要这样

cat mydata.txt|sort|uniq>mydata.txt


管道构建时,这些命令是同时进行的,uniq>mydata.txt会清空掉mydata.txt

作为程序设计语言的shell

和python等比较相似,比较简单的shell语句是可以直接在bash上运行的。

例如:

#!/bin/sh
#称之为glob通配符
for file in *
do
#如果在file中找到了'include'
if grep -l include $file
then
echo $file
fi
done
#退出 返回一个有意义的退出码
exit 0


接下来需要把脚本设置为可执行权限:

chmod +x mysh.sh


然后

./mysh.sh


加上
.
是因为bash的环境变量PATH中没有当前路径。

shell的语法

变量

shit=shitshit
fuck="fuckfuck"
you=1+3
echo $shit,$fuck,$you


这就是shell的命名方法,创建变量时不需要,但在获取它的值的时候必须加,但在获取它的值的时候必须加。

上面三种变量都是多少?

都是字符串:

shitshit,fuckfuck,1+3


读取输入赋值

read shit


环境变量

变量名说明
$HOME当前用户家目录
$PATHshell用来搜索命令的目录
$0当前shell脚本名称
$#传递给脚本的参数个数
$$进程PID
参数变量

变量名说明
$1,$2,$3脚本程序的参数
$@一个分割开的字符串
一个应用实例是:

打印出所有的参数名称:

#!/bin/bash
for i in $@
do
echo $i
done
exit 0




./my.sh 1 2 3
1
2
3


条件

判断某一个文件是否存在:

if test -f mysh.sh
then
echo shit you are here
fi


或者这种:

if [ -f mysh.sh ]
then
echo shit
fi


(是不是shell编程很累啊?相比之下python的方式就要友好得多,靠缩进来说明结构,不需要then fi do done这些语句。但是这么做肯定是由当年的一些限制在里边。python要到1989年才能发明出来~)

[ -f mysh.sh ]可以看做test命令的变种。除了进行文件测试外:

还可以有字符串、算术等。具体可以看这里

控制结构

我们之前已经有提及到其控制结构了:

if condition
then
statements
elif
statements
else
statements
fi


for循环一般是字符串

for variable in values
do
statements
done


但是这样很明显太弱了,for还可以用通配符来拓展:

#!/bin/bash
for file in $(ls f*.sh)
do
#打印文件
lpr $file
done
exit 0


需要特别注意的是在ls f*.sh上加上$()

while语句:

while condition do
statement
done


朴素的密码验证

#!/bin/bash
echo "print your password"
read word

while [ "$word" != "secret" ]
do
echo "Sorry,try again"
read word
done
exit 0


你会注意到$word加了一个引号,这么做是为了防止如下情形:

当word为空时,则变成了[ !=”secret” ]

case语句:

case  variable in
pattern[|pattern]...) statements;;
pattern[|pattern]...) statements;;
esac


一个小栗子:

#!/bin/bash

echo "yes or no?(y/n)"
read  yn
case "$yn" in
y|yes|ok) echo "confirmed!"
echo "successfully";;
n|no|n*)  echo "canceled";;
*) echo "you say what?";;
esac
exit 0


1.注意pattern其实是支持通配符的,*代表了一个字符串

2.注意一个case下可以有多条语句

函数

shell的函数可能看起来不怎么严谨。

function_name(){
statements
}


没有返回类型,没有参数类型。

我们只谈两三个简单的例子:

捕获返回结果

foo(){echo JAY;}
...
result="$(foo)"


一个复杂的点的返回0或1的函数

#!/bin/bash
yesno(){
echo "is your name $* ?"
while true
do
echo -n "Enter yes or no:"
read x
case $x in
y*) return 0;;
n*) return 1;;
*) echo "you say what ?"
esac
done
}

echo "原始参数是: $*"
if yesno "$1"
then
echo "OK"
else
echo "Well..."
fi
exit 0


命令

我认为比较重要的有:

exec命令

exit n命令

expr命令

之前说过,无论是单引号双引号还是都是字符串。

类似于
s=1+2
这样得到的结果只是一个字符串
1+2


正确的用法是:

x=`expr 1 + 2`
#或者
x=$(expr 1 + 2)


你是否注意到这个
$
的作用?我们之前在for的用法中也用到过,如果忘记了请往回看看。

需要注意的是expr是一个命令,后面这个表达式每一个之间都有一个空格,这样命令才能正确识别。

如果我们要实现x的自加

x=$(expr $x + 1)


printf命令

基本形式是:

printf "format string" parameter1 parameter2...


示例

printf "%s %d \t%s" "Hi There" 15 people


“Hi There”之所以也有双引号是因为需要将其看做一个整体。这一技巧还会在很多地方看到。

trap

在Shell编程中比较常用的两个外部命令:

find

find [path] [options] [test] [actions]


find的具体指令请看这里

另一个是grep

grep [options] PATTERN [FILES]


例如之前我们提到过的

grep -l include *
#搜索当前目录下的所有带有"include"的文件名


具体用法看这里
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: