Linux系统之shell程序设计(理论+实战)

一、shell简介

1.1 什么是shell?

1.2 为什么要学习shell?


◼Shell是Linux的用户接口

◼简单易用的命令组合完成复杂任务

◼强大的综合处理功能

◼一生受用好工具
...

1.3 shell 有哪些种类?

◼/bin/csh(c-like shell)
◼/bin/ksh(kornshell, by AT&T Bell LAB)
◼/bin/tcsh(enhanced csh, FreeBSD default login shell)
◼/bin/bash (bourne-again shell)
◼/bin/dash
◼当前系统安装的Shell可以通过cat /etc/shells 查看
◼用户的默认登录Shell可以通过cat /etc/passwd查看tom:x:500:500:tom:/home/tom:/bin/bash
...

二、bash基础

2.1 bash的内部命令

Bash集成了一些内部命令,组成基本操作环境
常用的内部命令:
:(true).(source) alias bgbind builtincd declare dirsdisown echo enable evalexec exit export fc fggetoptshash help history jobs kill let local logout popdpushdpwdread readonlyreturn set shift stop suspend test times trap typestultimitumaskunaliasunset wait
循环分支控制相关:
if else eliffi for do done case while until continue break

2.2  bash的初始化脚本

通常在这些脚本中进行自定义设置,比如一些程序的环境变量等
 

/etc/profile
/etc/bashrc
˜/.bash_profile
˜/.bashrc
˜/.profile

2.3 bash的执行方式(交互式)

Linux终端登录后,即进入交互式的执行环境
可以执行内部及外部命令

foo@localhost> ls
a.txt b.txt c.txt
foo@localhost> hostname
localhost
后台执行: command &
foo@localhost> sleep 300 &

2.4 bash的执行方式(脚本方式)

脚本执行方式,将Bash语句写在文本文件中,批量执行
#开头表示注释
不开启子Shell,在当前Shell中运行:

foo@localhost> source test.sh
foo@localhost> . test.sh
foo@localhost> eval`cat test.sh`


在新的子Shell中运行:

foo@localhost> bash -c 'commands'
foo@localhost> bash test.sh
foo@localhost> ./test.sh(需要test.sh具有可执行权限)
(脚本文件以#!/bin/bash开头,且具有可执行权限)

2.5 bash命令的组合方式

不同的命令可分行放置,也可以用分号隔开
 

#!/bin/bash
cd subdir1
rma.txt
foo@localhost> cd /home/foo/subdir2; rmb.txt

2.6 bash命令的组合方式(逻辑组合)

管道线分隔符
command1 && command2 (前者执行成功才执行后者)
command1 || command2 (前者执行失败才执行后者)
foo@localhost> cd /home/foo && rmb.txt
foo@localhost> cd /home/foo || echo "dirdoes not exist!"

 2.7 bash命令的组合方式(命令集合)

命令集合
{ commands;}
命令集合,在当前Shell执行,注意{}前后的空格和分号
(commands)
开启新的子Shell执行
foo@localhost> {cd /home/foo; rma.txt;}
foo@localhost> (cd /home/foo; rma.txt)

 2.8 bash命令的别名设置(alias)

可以定义一些命令的别名,方便使用,别名设置可以放在Bash的初始化脚本中自动加载

foo@localhost> alias ll='ls-l --color=tty'
foo@localhost> alias ll
alias ll='ls -l --color=tty'
foo@localhost> alias rm='rm-i'
foo@localhost> unaliasll
 取消别名

2.9 bash的变量

变量申明、查看、清除
var=value#注意=号前后无空格
echo $var
unset var
foo@localhost> var1=abc
foo@localhost> echo $var1
abc
foo@localhost> unset var1
foo@localhost> echo $var1
(无输出)

2.10 bash的变量(系统变量)

常用系统变量:
HOSTNAME
TERM
PATH
HOME
PWD
SHELL
...
foo@localhost> echo $SHELL
/bin/bash
foo@localhost> echo $HOME
/home/foo

2.11 bash的变量(全局变量) 

全局变量(子Shell会继承)
export var=value
foo@localhost> export var1=abc
foo@localhost> var2=123
foo@localhost> export var2
foo@localhost> bash -c 'echo $var1 $var2'
abc123

2.12 bash的变量(特殊变量) 

$?前一个命令的退出状态,正常退出返回0,异常退出返回非0值
$#脚本或函数参数的个数
$0脚本或函数的名称
$1,$2, ...传递给脚本或函数的位置参数
$*以”$1 $2...”的形式保存所有输入的命令行参数
$@以“$1”“$2”...的形式保存所有输入的命令行参数

foo@localhost> cat test.sh
#!/bin/bash
echo "The command is $0 $1 $2"
foo@localhost> ./test.sh arg1 arg2
The command is test.sh arg1 arg2

foo@localhost> ls
a.txt b.txt
foo@localhost> echo $?
0
foo@localhost> ls c.txt
ls: cannot access c.txt: No such file or directory
foo@localhost> echo $?
2

2.13 bash的通配符

通配符
* 配任何字符串,包括空字符串
?匹配任何单个字符
[] 按照字符范围或列表匹配
{...,...} 按照字符串列表匹配
\转意符,使元字符失去其特殊的含义

foo@localhost> ls*.txt
foo@localhost> lsA0?.txt
foo@localhost> ls[A-Z,a-z][0-9].txt
foo@localhost> ls[!a-z]*.txt
foo@localhost> lsabc.{txt,tar,dat}
foo@localhost> echo \*

2.14 bash的命令替换

命令替换:把命令的输出结果字符串直接替换进来
`commands` 注意是反引号,不是单引号
$(commands)

foo@localhost> echo `date`
Sun Jan 9 15:38:00 2011
foo@localhost> files=`ls`
foo@localhost> currentdir=$(pwd)

2.15 bash的变量参数替换

${variable-default}
如果变量没有定义,则返回默认值;
如果变量已定义,则返回变量值,变量值不变;
注意:变量定义成空字符串也算定义

foo@localhost> echo $username
无输出
foo@localhost> echo ${username-`whoami`}
foo
foo@localhost> echo $username
无输出

2.16 bash的变量参数替换 (续1)

 ${variable=default}
如果变量没有定义,返回默认值,且赋值给变量;
如果变量已定义,则返回变量值,变量值不变;

foo@localhost> echo $username
无输出
foo@localhost> echo ${username=`whoami`}
foo
foo@localhost> echo $username
foo

2.17 bash的变量参数替换 (续2) 

${variable+value}
如果变量已经定义,返回+号后给定值,如果没有,返回空
${variable?msg}
如果变量已经定义,返回变量本身,如果没有,打印给定msg

2.18 bash的变量字符串操作(子串提出) 

${#string}返回字符串的长度
${string:position}提取从指定位置开始的子串
${string:position:length}提取从指定位置开始的定长子串 

foo@localhost> string=01234
foo@localhost> echo ${#string}
5
foo@localhost> echo ${string:2}
234
foo@localhost> echo ${string:2:2}
23

2.19 bash的变量字符串操作(子串裁剪)

${string#substring}裁去从左边最短匹配子串
${string##substring}裁去从左边最长匹配子串
${string%substring}裁去从右边最短匹配子串
${string%%substring}裁去从右边最长匹配子串
如果子串不匹配,不做裁剪操作

foo@localhost> string=abc.txt
foo@localhost> echo ${string#abc}
.txt
foo@localhost> echo ${string%.*}
abc

 2.19 bash的变量字符串操作(子串替换)

${string/substring/replace}替换第一处匹配
${string//substring/replace}替换所有匹配
如果子串不匹配,不做裁剪操作

如果子串不匹配,不做裁剪操作

foo@localhost> string=black-black
foo@localhost> echo ${string/black/white}
white-black
foo@localhost> echo ${string//black/white}
white-white

2.20 bash的变量数组(Array) 

foo@localhost> array=(dog fish cat)
foo@localhost> echo ${#array[*]}
3
foo@localhost> echo ${array[*]}
dog fish cat
foo@localhost> echo ${array[0]}
dog

2.21 bash的终端控制(输入输出重定向)

Linux 默认的三个I/O 通道:
stdin(标准输入,文件描述符:0)–默认是键盘
stdout(标准输出,文件描述符:1)–默认是终端
stderr(标准错误,文件描述符:2)–默认是终端

<重定向stdin到文件
>重定向stdout到文件(新建或覆盖)
>>重定向stdout到文件(追加)
2>重定向stderr到文件(新建或覆盖)
2>>重定向stderr到文件(追加)
2>&1重定向stderr到stdout
>&重定向stdout和stderr到文件

2.22 bash的终端控制(输出重定向)

foo@localhost> ls *.{txt,dat}
ls: cannot access *.txt: No such file or directory
a.dat b.dat
foo@localhost> ls *.{txt,dat} >/tmp/ls.out
ls: cannot access *.txt: No such file or directory
foo@localhost> cat /tmp/ls.out
a.dat b.dat
foo@localhost> ls *.{txt,dat} >/tmp/ls.out2>/tmp/err.out
foo@localhost> cat /tmp/err.out
ls: cannot access *.txt: No such file or directory

2.23 bash的终端控制(输入重定向)

命令的输入定向到文件,而不是从键盘输入

foo@localhost> tr'a-z' 'A-Z' </etc/hosts
foo@localhost> tr'a-z' 'A-Z' </etc/hosts >result.log

2.24 bash的终端控制(重定向到特殊文件)

 可以重定向到特殊字符设备文件
e.g.
foo@localhost> ls >result.log 2>/dev/null

注:Linux下常用的特殊字符设备文件:
/dev/null ——“空文件”或“黑洞文件”,丢弃一切写入的内容
/dev/zero ——永远提供NULL空字符

2.25 bash的终端控制(管道符)

管道符pipe(|),将命令的输出定向到下一条命令的输入

foo@localhost> ls/usr/lib | less
foo@localhost> cut -f1 -d: /etc/passwd| sort -r | less
foo@localhost> cut -f1 -d: /etc/passwd| sort -r > result.log

2.26 bash读入变量(read)

使用内部命令read,可以从终端读入Shell变量
与C语言的scanf()类似
格式:read [-p 提示字符] var1 [var2]

foo@localhost> cat read_test.sh
#!/bin/bash
read name age
echo $name is $age years old.
foo@localhost> ./read_test.sh
输入Bob 17,按Ctrl-d
Bob is 17 years old.
foo@localhost> echo Bob 17 | ./read_test.sh
Bob is 17 years old.

2.27 bash中的引号 

单引号屏蔽所有特殊字符

foo@localhost> echo '$HOME'
$HOME
foo@localhost> echo "$HOME"
/home/foo
foo@localhost> echo " '$HOME' "
'/home/foo'
foo@localhost> echo " \"$HOME\" "
"/home/foo"

2.28 Bash中的数学运算(内部命令) 

内置命名let 或((...)),只能用于整型运算
foo@localhost> echo $(( (1+1)*(2*2) ))
8
foo@localhost> a=1
foo@localhost> ((a+=1))
foo@localhost> echo $a
2
foo@localhost> a=1
foo@localhost> let a+=1
foo@localhost> echo $a
2

2.30 Bash中的数学运算(外部命令) 

调用外部命令expr,只能用于整型运算
foo@localhost> expr\( 1 + 1 \) \* \(2 \* 2 \)
8
foo@localhost> a=`expr1 + 1`
foo@localhost> echo $a
2
注意括号和运算符前后有空格

2.31 Bash中的数学运算(外部命令) 

调用外部命令bc,可用于浮点运算,功能强大
foo@localhost> echo '1.2*1.2' | bc-l
1.44
foo@localhost> echo "ibase=10; obase=2; 10" | bc
1010

2.32 Bash中的逻辑判断 

内部命令test,可用于数字比较、字符串比较、文件状态检查、逻辑判断等。语法:
test condition
或
[ condition ] #注意[]前后的空格
如果condition成立,返回0,不成立返回非0
foo@localhost> test 1 == 1;echo $?
0
foo@localhost> [ 1 == 2 ]; echo $?
1

2.33 Bash中的逻辑判断(字符串比较) 

=或==两个字符串相等
!=两个字符串不等
-z空字符串
-n非空字符串
=~与正则表达式regex进行比较

foo@localhost> str="abc"
foo@localhost> [ "$str" = "abc" ] && echo "true"
true
foo@localhost> [ -z "$str" ] && echo "true"
无输出

2.34 Bash中的逻辑判断(整数比较) 

-eq或==两个整数相等
-ne或!=两个整数不等
-gt或>前者大于后者
-ge或>=前者大于等于后者
-lt或<前者小于后者
-le或<=前者小于等于后者

foo@localhost> var=1
foo@localhost> [ $var>= 1 ] && echo "true"
true
foo@localhost> [ $var< 0 ] && echo "true"
无输出

2.35 Bash中的逻辑判断(文件状态判断) 

-d所判断文件是一个目录
-f正规文件(Regular file)
-L符号链接
-r Readable(文件、目录可读)
-w Writable(文件、目录可写)
-xExecutable(文件可执行、目录可浏览)
-u文件有suid权限标志
-s文件长度大于0,非空
-z文件长度等于0

foo@localhost> file=/etc/hosts
foo@localhost> [ -r $file ] && echo "read permission OK"
read permission OK

2.36 Bash中的逻辑判断(逻辑操作符) 

condition1 -acondition2逻辑与
condition1 -o condition2逻辑或
!condition逻辑取非

foo@localhost> a=2; b=3
foo@localhost> [ $a > 1 -a$b > 1 ] && echo "true"
true
foo@localhost> [ !$a > 1 ] && echo "true"
无输出

 2.37 Bash中的分支判断(if语句)

if condition_judgement
then
...
fi
if condition_judgement1
then
...
elif condition_judgement2
then
...
else
...
fi
if condition_judgement
then
...
else
...
fi

2.38 Bash中的分支判断(if语句) 

举例

#!/bin/bash
if [ $1 > 1 ]
then
echo "Greater than 1"
elif [ $1 < 1 ]
then
echo "Less than 1"
else
echo “Equals to 1"
fi
#!/bin/bash
if cd /tmp/test &>/dev/null
then
echo “Entering dir succeeds"
fi

 条件判断也可以是命令,执行成功表示真

2.39 Bash中的分支判断(case语句)

case expression in
pattern1)
...;;
pattern2)
...;;
...
patternn)
...;;
esac
case expression in
pattern1)
...;;
pattern2)
...;;
...
patternn)
...;;
*)
...;;
esac

 举例:

#!/bin/bash
case $1 in
apple)
echo "You choose apple";;
grape)
echo "You choose grape";;
*)
echo “I have only apple and grape";;
esac

 2.40 Bash中的循环控制(for循环)

for var in value_list
do
...
done
for ((var=0; var<=10; var++))
do
...
done

举例

for name in tom bob cindy
do
echo $name
done
for i in `seq 1 10`
do
ssh node$i date
done


变量取值也可以来自
其它命令的输出
for ((i=0; i<=10; i++))
do
echo $i
done

 2.41 Bash中的循环控制(while循环)

while condition_judgement
do
...
done

条件判断可以是:
test 或[ .. ] 语句
◼其它命令,判断其执行成功与否
true 或: (Bash的内部命令,代表真,使得while成为无限循环) 

举例一:

COUNTER=0
# If COUNTER < 5, program will print the value of it.
while [ "$COUNTER" < 5 ]
do
COUNTER=$((COUNTER+1))
echo $COUNTER
done

举例二:不停地从终端读入一个整数,输入9则退出

NUMBER=0
while [ "$NUMBER" != "9" ]; do
read -p 'Enter a integer, 9 to exit' NUMBER
echo You typed is $NUMBER
done

2.42 Bash中的循环控制(until循环) 

until condition_judgement
do
...
done


与while循环语法一致,但意思“相反”,没有while循环常用
until循环是先执行循环,直到满足判断条件后跳出

 2.43 Bash中的函数

在Shell 中,函数就是一组实现一定功能的命令集合;
函数由两部分组成:
函数名(在一个脚本中必须唯一);
函数体(命令集合);

function_name()
{
...
}
#先定义,后使用
function_name

 2.44 Bash中的函数(函数参数)

举例:交换两个文件的文件名

swap_filename()
{
file1=$1
file2=$2
cp $file1 file1.bak
mv $file2 $file1
mv $file1.bak $file2
}

2.45 Bash中的函数(函数的退出状态) 

函数结尾可以掉用return语句返回执行状态,0表示无错误
举例:

check_file_lines()
{
file=$1
lines=`wc -l $file`
if [ $lines -gt 1000 ]; then
return 0
else
return -1
fi
}
check_file_lines result.log && echo "file is long enough"

三、bash进阶

3.1 正则表达式regex

正则表达式:进行精确文字匹配的句法规则;比通配符强大无数倍

Regex的基本元字符集:

 3.2 正则表达式regex(续1)

Regex的扩展元字符集:

3.3 字符查找工具grep 

grep 是Linux 下使用最广泛的命令之一,其作用是在一个或多个文件中查找
某个字符模式所在的行,并将结果输出到屏幕上
grep 以行为单位进行处理,不会对输入文件本身进行修改

grep 家族由grep、egrep 和fgrep 组成:
◆ grep: 标准grep 命令,本文主要讨论此命令。
◆ egrep: 扩展grep,支持基本及扩展的正则表达式。
◆ fgrep: 固定grep (fixed grep),按字面解释所有的字符,即正则
表达式中的元字符不会被特殊处理。

3.4 字符查找工具grep(续1)

❑ grep 命令的一般形式:
grep [选项] pattern file1 file2 ...
grep -f patternfile file1 file2 ...
⚫ pattern:可以是正则表达式(用单引号括起来)、
或字符串(加双引号)、或一个单词。
⚫ file1 file2 ... :文件名列表,作为grep 命令的输入;grep 的输入也可以来自标准输
入或管道;
❑ 可以把匹配模式写入到一个文件中,每行写一个,然后使用-f 选项,将该匹配模式传
递给grep 命令

3.5 字符查找工具grep (续2)

grep 常用选项

grep -i 'an*' datafile

3.6 字符查找工具grep(举例)

查找包含字符串Hello的行
grep 'Hello' datafile
查找以#开头的行
grep '^#' datafile
查找非空行并另存
grep -v '^$' datafile >datefile2
与管道符连用
cat /etc/hosts | grep 'node' | wc -l

3.7 字符流编辑工具sed

sed 是什么?

sed 是一个精简的、非交互式的编辑器
sed 如何工作?
sed 逐行处理文件(或输入),并将输出结果发送到屏幕。
即:sed 从输入(可以是文件或其它标准输入)中读取一行,将之拷贝到一个
编辑缓冲区,按指定的sed 编辑命令进行处理,编辑完后将其发送到屏幕上,
然后把这行从编辑缓冲区中删除,读取下面一行。重复此过程直到全部处理结
束。
sed 只是对文件在内存中的副本进行操作,所以sed 不会修改输入文件的内容。
sed 总是输出到标准输出,可以使用重定向将sed 的输出保存到文件中。

3.8 字符流编辑工具sed(续1)

sed的命令行调用方式
sed [-n][-e] 'sed_cmd' input_file
⚫ -n:缺省情况下,sed 在将下一行读入缓冲区之前,自动输出行缓冲区中的内容。此
选项可以关闭自动输出。
⚫ -e:允许调用多条sed 命令,如:
sed -e 'sed_cmd1' -e 'sed_cmd2' input_file
⚫ sed_cmd:使用格式: [address]sed_edit_cmd (通常用单引号括起来),其中
address 为sed 的行定位模式,用于指定将要被sed 编辑的行。如果省略,sed 将编
辑所有的行。sed_edit_cmd 为sed 对被编辑行将要进行的编辑操作。
⚫ input_file:sed 编辑的文件列表,若省略,sed 将从标准输入(重定向或管道)中
读取输入。

3.9 字符流编辑工具sed (续2)

◆ 也可以将sed 命令存在脚本文件,然后调用

sed [选项] -f sed_script_file input_file
◆ 将sed 命令插入脚本文件,生成sed 可执行脚本文件,在命令行中直接
键入脚本文件名来执行。
#!/bin/sed -f
sed_cmd1
... ...
例:sed -n -f sedfile1 datafile

例:./sedfile2.sed -n datafile

3.10 字符流编辑工具sed(续3)

sed_cmd中address的定位方式

3.11 字符流编辑工具sed (续4)

❑ 常用的sed_edit_cmd

◆ p :打印匹配行
       sed -n '1,3p' datafile
       sed -n '$p' datafile
       sed -n '/north/p' datafile
◆ = :显示匹配行的行号
       sed -n '/north/=' datafile
◆ d :删除匹配的行
       sed -n '/north/d' datafile
❑ 常用的sed_edit_cmd

3.12 文本和数据编辑工具awk

❑awk 是什么?

awk是一种对文本和数据进行处理的编程语言。


❑awk 如何工作
awk是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入(stdin)、一个或多个文件,或其他命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。awk有很多内建的功能,比如数组、函数等。

3.13 文本和数据编辑工具awk(续1) 

◆awk对字段(列)的提取
字段提取:提取一个文本中的一列数据并打印输出,用逗号分隔字段内置变量打印。
字段相关内置变量:
•$0:表示整行文本
•$1:表示文本行中的第一个数据字段
•$2:表示文本行中的第二个数据字段
......
•$N:表示文本行中的第N个数据字段
•$NF:表示文本行中的最后一个数据字段

awk 默认的分隔符是空格 

3.14 文本和数据编辑工具awk(续2) 

提取第一列数据:

提取第1,3列数据:

 3.15 文本和数据编辑工具awk(续3)

指定分隔符提取列数据:
awk -F ":"'{print $2}' mytest

打印第1列和最后一列数据:

 3.16 文本和数据编辑工具awk(续4)

指定分隔符提取列数据:
awk -F ":"'{print $2}' mytest

3.17 文本和数据编辑工具awk(续5) 

awk记录(行)的提取
记录提取:提取一个文本的一行并打印输出。
•用逗号:分隔行号打印;NR==1,NR==3:打印1至3行
•用冒号;分割行号打印;NR==1;NR==3:打印1和3行
•记录的提取方法有两种:通过行号提取和通过正则表达式。
•记录相关内置变量:NR==4
awk 默认的分隔符是空格

3.18 文本和数据编辑工具awk(续6)

提取第四行全部数据:
awk 'NR==4{print $0}' mytest

3.19 文本和数据编辑工具awk(续7) 

指定分隔符提取第四行第五个字段:
awk -F":" 'NR==4{print $5}' mytest

3.20 文本和数据编辑工具awk(续8) 

打印多行,同时指定输出列的位置(NR==1,NR==3:代表1到3行)=> 逗号分隔符
awk 'NR==1,NR==3{print $6,$3,$4}' mytest1

3.21 文本和数据编辑工具awk(续9) 

打印多行,分割awk程序:=> 冒号分割
awk 'NR==1;NR==3{print $1,$6,$3,$4}' mytest1

  • 60
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

技术瘾君子1573

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值