shell 皮毛学习
序?
先写一个皮毛学习,估计连皮毛学习都不算🤭。后面有时间在补充深入学习🐊(到处留小尾巴)。
额,为啥要学习呢,实际上是因为学习nginx
的时候涉及到使用shell
脚本实现日志切割。所以想先了解下shell
(反正行走江湖,技多不压身。了解一下)。学习资料就时shell脚本学习指南.pdf
本来想上传一个免费的上去,不过发现存在重复资源。有需要的可以留言或者私信我留下邮箱。当然网上也有免费资源可以下,只是需要找啦。当然这一篇是不可能有太多东西的,所以基本营养不多,都是基本的,路过的大神多多指点
前言
Shell脚本的三大特性:
-
简单性:高级解释型语言,可以简洁的表达复杂的操作。
-
可移植性:使用POSIX定义的功能,使得脚本无需修改就可在不同系统上执行。
-
易开发:耗时短。即短时间内就可以完成一个功能强大又好用的脚本。
# 授权
chmod +x
第一个shell脚本
#!/bin/bash -
who | wc -l
Tip: #! /bin/bash -
中的-
表示没有shell选项;基于安全考虑,可避免某种程度的欺骗式攻击。#!前后不能有空格等其他字符,否则,执行脚本失败"-bash: ./finduser: bin/sh: bad interpreter: No such file or directory"
几个初级陷阱:
- 当今的系统,对
#!
这行的长度限制从63到1021字符都有,尽量不要让这行长度超过64位字符 - 脚本是否可移植取决于是否又完整的路径名称
- 选项之后不要防止任何空白,因为空包会跟着选项一起传递给引用的程序
- 需要知道解析器的完整路径名称。这可以用来规避可移植问题
shell的基本元素
1、命令与参数
- 内建命令:Shell本身所执行的命令,为了其必要性和效率,例:cd、 read 、test、echo、 printf等。
- shell函数:功能健全的一系列程序代码,以Shell语言写成,它们可以像命令那样引用
- 外部命令:由Shell的副本(新的进程)所执行的命令
一些常见的命令
who:当前系统上登录用户
echo:标准输出
printf:与echo相比,需要在结尾使用\n换行.
基本的I/O重定向:标准输入/输出(<)、标准错误输出(>)----默认三者在终端
tr:translate的简写,主要用于压缩重复字符,删除文件中的控制字符以及进行字符转换操作。
-s:压缩字符
-d:删除字符
-t:字符替换,可以省略
格式:echo "abcddel" | tr -d "d" ====> adcel
|:建立管道,program1|program2 //前一个的标准输出为后一个的标准输入
#:注释grep:查找可配合+正则表达式 🐊
# cut:切分文件,具体参考🐊
# awk:一个强大的文本分析工具。🐊
2、变量
不需要声明类型,直接创建即可。
变量的初始值都为空(null)且变量赋值是没有长度限制的,这里要注意shell
中变量赋值的时候不要存在空格
# 错误
a = jimmy
# 正确
a=jimmy
- 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。
- 中间不能有空格,可以使用下划线(_)。
- 不能使用标点符号。
- 不能使用bash里的关键字(可用help命令查看保留关键字)。
#!/bin/bash
_name=jimmy
echo $_name
echo ${_name}
echo _${name}_
echo _$_name_
##### 下面为输出结果
> ./variablePrc
jimmy
jimmy
_jimmy_
_
# 这里最后一种形式不是我们想要的结果,只是错误示例展示
POSIX Shell中其他的内置变量:显示时都是$…
?:前一个命令的退出状态
$:Shell进程的进程编号(process ID)
0:Shell程序的名称
!:最近一个后台命令的进程编号.
IFS:内部的字段分隔器.例如单词分隔,一般为空格、制表符或换行.
HOME:根目录
LANG:当前locale的默认名称
PATH:命令的查找路径
PPID:父进程的进程编号
PWD:当前工作目录
POSIX Shell的结束状态:
0:在重定向或单词展开期间
1-125:命令不成功地退出
126:命令找到了,但文件无法执行
127:命令找不到
128:未定义
可以使用exit命令传递一个退出值给它的调用者,退出脚本。
3、echo和printf
echo命令涉及内容比较多,以后会单独进行学习🐊。这里只是简单的说明下
> echo jimmy
jimmy
> echo 'jimmy'
jimmy
> echo "jimmy"
jimmy
> echo "jimmy!"
# 双引号不能打印感叹号 关于这部分后面我们在进行实验学习
-bash: !": event not found
echo 遇到转义序列时,会打印相应的字符。有效的转移序列如下:
序列 | 说明 |
---|---|
\a | 警示字符,通常是ASCII的BEL字符 |
\b | 退格 |
\c | 输出是忽略最后的换行字符,这个参数之后的任何字符都会被忽略 |
\f | 清除屏幕 |
\n | 换行 |
\r | 回车 |
\t | 水平制表符 |
\v | 垂直制表符 |
\ | 反斜杠字符 |
\0ddd | 将字符表示成1到3的八进制数值 |
由于echo有版本上的差异,有UNIX版本间可移植性问题。因此使用printf命令来处理。
printf
命令模仿了C
的printf()
。几乎复制了该函数的功能
# 这里可以发现 printf不会像echo一样进行
> printf 'jimmy'
jimmy >
printf的完整语法:
printf format-string [ars…]
format-string: 用来描述输出的排列方式,最好为此字符串加上引号
ars:是与格式声明像对应的参数列表
printf只是格式化输出,不会改变任何结果,所以在格式化浮点数的输出时,浮点数结果是不变的,仅仅只是改变了显示的结果。注意看示例里面的浮点数展示
# printfPrc1
#!/bin/bash
printf "%-5s %-10s %-4s\n" No Name Mark # 三个%分别对应后面的三个参数
printf "%-5s %-10s %-4.2f\n" 1 Sarath 80.34 # 减号“-”表示左对齐
printf "%-5s %-10s %-4.2f\n" 2 James 90.998 # 5s表示第一个参数占用5个字符
printf "%-5s %-10s %-4.2f\n" 3 Jeff 77.564
> ./printfPrc1
No Name Mark
1 Sarath 80.34
2 James 91.00
3 Jeff 77.56
printf中还可以加入分行符、制表符等符号。
# printfPrc2
#!/bin/bash
printf "%-s\t %-s\t %s\n" No Name Mark
printf "%-s\t %-s\t %4.2f\n" 1 Sarath 80.34
printf "%-s\t %-s\t %4.2f\n" 2 James 90.998
printf "%-s\t %-s\t %4.2f\n" 3 Jeff 77.564
> ./printfPrc2
No Name Mark
1 Sarath 80.34
2 James 91.00
3 Jeff 77.56
更多详细的以后在进行逐一学习🐊
4、I/O重定向、管道
-
<
改变(标准)输入 a < file表示a的输入修改为file
-
>
该表(标准)输出 a > file表示a的输出到file
-
>>
附加到文件 a >> file 将a的输出附加到 file的结尾处 -
|
建立管道 command1 | command2 将 C1的标准输出修改为 C2的标准输入管道命令是可以将俩个程序联通,如果使用
<
>
等需要写如临时文件,然后在执行,这样效率就打打降低了
几个命令是可以结合使用的(下面的例子我没有自己试验,是PDF里面的)
# tr 命令可以查下是啥意思
> tr -d '\r' < dos-file.txt
> tr -d '\r' < dos-file.txt > UNIX-file.txt
> tr -d '\r' < dos-file.txt | sort > UNIX-file.txt
-
特殊文件(用的比较少,需要的时候在来学习)
-
/dev/null
if grep pattern myfile > /dev/null
then
… 找到模式时
else
… 未找到模式时
fi
-
/dev/tty
-
5、环境变量
$PATH
表示环境变量,具体环境变量是干啥的我就不说了😂
> echo $PATH
bin:/usr/local/git/bin:/usr/local/git/bin:/home/ybyy/bin
这里可以windows不同,linux的环境变量分隔符未:
当然我们也可以修改环境变量
PATH = $PATH:$HOME/mybin
Shell脚本的循环、条件、计算、判断
1、替换运算符
${var:-jimmy}:若var存在且非null,则返回其值;否则,返回jimmy.
用途:若变量未定义,返回默认值.
${var:=jimmy}:若var存在且非null,则返回其值;否则,设置其为jimmy,并返回值.
用途:若变量未定义,设置默认值.
${var:?msg}:若var存在且非null,则返回其值;否则,显示var:msg,并退出当前命令或脚本.
用途:为了捕捉由于变量未定义所导致的错误.
${var:+jimmy}:若var存在且非null,则返回jimmy;否则,返回null.
用途:为测试变量的存在.
例如:若count已定义,则${count:+1}返回1.
2、模式匹配运算符:
${path#/*/}
${path%.*}
${#var}:返回var值里的字符串长度.
#匹配的是前面(左),
%匹配的是后面(右).
//,匹配任何位于两个斜杠之间的元素;.,匹配点号之后接着的任何元素.
3、位置参数:
Shell脚本中的命令行参数;同时也表示Shell函数中的函数参数。其名称由单个整数命名,且当这个整数大于9时,需{}
echo arg1 is $1
echo arg10 is ${10} //表示命令行的第10个参数
$#:统计参数总数.
∗ 、 *、 ∗、@:将所有命令行参数视为单个字符串.
“ ∗ " : 带 双 引 号 , 将 所 有 命 令 行 参 数 视 为 一 个 字 符 串 . " *":带双引号,将所有命令行参数视为一个字符串. " ∗":带双引号,将所有命令行参数视为一个字符串."@”:带双引号,保留真正的参数值,即显示正确的参数.【正确显示命令行参数】
shift:截去来自列表的位置参数,由左开始.默认shift等同于shift 1,即将第一个参数移除
例: shift 10:截去第10个参数,若总数不足10个,则该语句不起作用
4、判断语句
# if -- then -- elif -- else --fi
# 写判断条件时,语法格式必须((...)),若以否定状态表达,则在条件前加入!即可.
i=168
if ((i<10))
then echo "<10"
elif ((i<200))
then echo "<200"
else
echo "fail"
fi
# case 每个条件用)结尾,且;;表示结束,类似java中的break,*表示默认匹配模式,类似java中的default。
case $1 in
10)
echo "10"
;;
2)
echo "2"
;;
*)
echo "other"
;;
esac
5、循环
# 简单的循环语句:
for i in "$@"
do echo i is $i
done
for var in item1 item2 ... itemN; do command1; command2… done;
for loop in 1 2 3 4 5
do
echo "The value is: $loop"
done
# while 循环
while condition
do
command
done
# until循环
until condition
do
command
done
6、Shell中自增的几种格式
((count++))
let count+=1
let count++
# $((...)):Shell中的算术运算。
# ((...)) 推荐--新写法
count=$((count+1))
# ``反引号,而非单引号,原始形式
count=`expr $((count+1))`