Shell(二)

什么是Shell
shell 是命令解释器,用于解释用户对操作系统的操作。

shell有很多
    cat /etc/shells

CentOS 7 默认使用的shell是bash
UNIX的哲学:一条命令只做一件事情
为了组合命令和多次执行命令,使用脚本文件来保存需要执行的命令
赋予该文件执行权限(chmod u+rx filename)
Shell脚本
Sha-Bang
命令
“#”号开头的注释
chmod u+x filename 可执行权限


执行命令
bash ./filename.sh   会生成一个子进程(不需要执行权限)
./filename.sh   会生成一个子进程,使用Sha-Bang (需要可执行权限)
source ./filename.sh  在当前进程运行
. filename.sh (点之后会产生一个子进程)

比如一个脚本如下:
#! /bin/bash
cd /tmp

在/home目录下运行
bash ./filename.sh 运行,子进程运行cd,然后子进程结束,此时pwd,还是在 /home 而不是/tmp

source ./filename.sh 或者 . filename.sh,这两个在/tmp,不产生子进程

内建命令和外部命令的区别
内建命令不需要创建子进程,内建命令比如source
内建命令对当前shell生效
管道和重定向

Shell管道是Shell中最值得称赞的功能之一,它以非常简洁的形式实现了管道的进程间通信方式,我个人认为Shell处理文本数据的半壁江山都来自于竖线形式的管道。像其它编程语言,打开管道后还要区分哪个进程写管道、哪个进程读管道,为了安全,每个进程还要关闭不用的读端或写端,总之就是麻烦,而Shell的管道非常简洁,竖线左边的就是写管道的,竖线右边的就是读管道的。

管道和信号一样,也是进程通信的方式之一
匿名管道(管道符)是 Shell 变成经常用到的通信工具
管道符是“|”,将前一个命令执行的结果传递给后面的命令
ps | cat
ps aux | grep 'sshd'
echo 123 | psecho 123 |cat |cmd 可以连续使用

注意一下输出重定向符

一个进程默认会打开标准输入、标准输出、错误输出三个文件描述符
输入重定向符号 “<”
read var < /path/to/a/file
read var1 < a.txt

输出重定向符号  ">"  ">>"  "2>" "&>"

echo 123 > /path/to/a/file   清空再输入
echo 123 >> /path/to/a/file  追加
2> 命令执行过程中有错误则重定向
&> 命令执行过程中无论正确错误都重定向 

输入和输出重定向组合使用
cat > /path/to/a/file.sh << EOF
i am $USER
EOF

运行以上三句话,会生成一个file.sh文件,文件里内容为i am $USER
变量

变量的赋值

变量名的命名规则

字母、数字、下划线
不以数字开头

变量的赋值

为变量赋值的过程中,称为变量替换
    变量名=变量值
    a=123  (不允许出现空格,shell会认为前面不是变量名而是一个命令,比如reboot =1),会重启

使用let为变量赋值
    let a=10+20 (尽量少用,效率很低)

将命令赋值给变量
    l=ls  (用处不大)

将命令结果赋值给变量,使用$() 或者 ''
    letc=$(ls -l /etc)
    letc='ls /root'

变量值有空格等特殊字符可以包含在 "" 或 '' 中
    srring1='hello bash'
    string2="hello I'm name"

变量引用和作用范围

变量的引用
    ${变量名}称作对变量的引用
    echo ${变量名} 查看变量的值
    ${变量名} 在部分情况下可以省略为 $变量名

变量的作用范围
    变量的默认作用范围
        当前的shell,父进程的变量对子进程无效,子进程的对父进程也无效。
        可以使用source
    变量的导出
        export ,子进程可以获得父进程的变量
        export demo_var1="hello subshell"
    变量的删除
        unset
        unset demo_var1

系统环境变量,预定义变量,位置变量

环境变量:每个Shell打开都可以获得到的变量
    set 和 env 命令
        env |  more 查看当前所有的环境变量
        echo ${HOME}  查看单个环境变量
    $PATH 当前命令的搜索路径
        所以要在$PATH 中新增路径,使用PATH=$PATH:新加路径(只对当前终端生效,对子shell生效)
    $PS1  当前提示终端

预定义变量
        echo $?  $$ $0等
        $?   指上一条命令是否正确执行,echo $?,正确执行返回0,错误1
        $$   显示当前进程 PID
        $0   显示当前进程名称

位置变量
    $1 $2 ... ${10},需要有{}

比如有脚本 test.sh]如下:
#! /bin/bash
pos1=$1
pos2=$2
echo $pos1
echo $pos2

执行的时候,./test.sh -a -l
会传参进去,可以对脚本进行简化
echo $1
echo $2

考虑到echo $2 的时候 $2 有可能是空值。所以写成下面这样
pos1=$1
pos2=${2}_
echo $pos1
echo $pos2
如果没有传参,则$2默认为_,规避读入的值是空值。但是这么写,如果传参进去,后面会多一个_,所以可以改成下面这样:
pos2=${2-_}

常见的环境变量

HOSTNAME=control_node
USER=root
HOME=/root
SHELL=/bin/bash
HISTSIZE=1000
SSH_TTY=/dev/pts/2
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
MAIL=/var/spool/mail/root
PWD=/root
LANG=en_US.UTF-8

常见的特殊变量

$1,$2,...,$N:脚本的位置参数
$0:shell或shell脚本的名称  
$*:扩展为位置参数,"$*"会将所有位置参数一次性包围引起来,"$*"等价于"$1_$2_$3..."
$@:扩展为位置参数,"$@"会将每个位置参数单独引起来,"$@"等价于"$1" "$2" "$3"...
$#:位置参数的个数
$$:当前Shell的进程PID,在某些子Shell(如小括号()开启的子Shell)下,会被继承。如果可以,建议使用$BASHPID替代$$
$?:最近一个前台命令的退出状态码  
$!:最近一个后台命令的进程PID
$-:当前Shell环境的一些特殊设置,比如是否交互式
$_:最近一个前台命令的最后一个参数(还有其它情况,该变量用的不多,所以不追究了)

需要注意一下的👍

关于$* "$*" $@ "$@"的区别,参见如下shell脚本测试:

#!/bin/bash

echo '$*----------':
for i in $*;do echo "<$i>";done

echo '"$*--------"':
for i in "$*";do echo "<$i>";done

echo '$@----------':
for i in $@;do echo "<$i>";done

echo '"$@--------"':
for i in "$@";do echo "<$i>";done


$ chmod +x position_parameters.sh
$ ./position_parameters.sh a b 'c d'
$*---------:
<a>
<b>
<c>
<d>
"$*--------":
<a b c d>
$@----------:
<a>
<b>
<c>
<d>
"$@--------":
<a>
<b>
<c d>

环境变量配置文件

配置文件
/etc/profile
/etc/profile.d/
~/.bash_profile
~/.bashrc
/etc/bashrc

所以经常在 /etc/profile 中新增 export PATH=$PATH:/new/path
su - 切换用户会加载4个文件
su 切换用户只会加载~/.bashrc、/etc/bashrc
数组
定义数组
    IPTS=(10.0.0.1 10.0.0.2 10.0.0.3)

显示数组的所有元素
    echo ${IPTS[@]}

显示数组元素个数
    echo ${#IPTS[@]}

显示数组的第一个元素
    echo ${IPTS[0]}
转义和引用
特殊字符:一个字符不仅有字面意义,还有元意(meta-meaning)
    # 注释
    ; 分号
    \ 转义符号
    " 和 ' 引号

单个字符的转义
    \n \r \t 单个字母的转义
    \$ \"  \\ 单个非字母的转义

引用
"" 双引号,如果里面有变量,会进行解释
'' 单引号不会进行解释
` 反引号
运算符
赋值运算符
= 赋值运算符,用于算数赋值和字符串赋值
使用 unset 取消为变量的赋值
= 除了作为赋值运算符还可以作为测试操作符


算数运算符

基本运算符
+ - * / ** %

使用expr进行计算
expr 4 + 5 (要有空格,只能支持整数)
num1=`expr 4 + 5`

数字常量的使用方法,如果不用特殊方法,a=4+5,其实把 “4+5”字符串赋值给a
let “变量名=变量值”
变量值使用0开头为八进制,0x开头为十六进制

双圆括号是let命令的简化
((a=4+5))
((a++))
echo $((10+20))
特殊符号大全
引号
    ' 完全引用
    " 不完全引用
    ` 执行命令
括号
    () (()) $() 圆括号
        单独使用圆括号会产生一个子shell(xyz=123)
        数组初始化 IPS=(ip1 ip2 ip3)

    [] [[]] 方括号
        单独使用方括号是测试(test)或数组元素功能
        两个方括号表示测试表达式
   
    <> 尖括号 重定向符号
    
    {} 花括号
        输出范围 echo{0..9},会输出0-9所有数字
        文件复制 cp -v /etc/passwd /etc/passwd.bak 
        等同于 cp -v /etc/passwd{,.bak}
运算和逻辑符号
    +-*/% 算数运算符
    ><= 比较运算符
    && || !逻辑运算符
        (( 5 > 4 && 6> 5)),然后通过 echo $? 判断
    
转义符号
    \

其他符号
    # 注释符
    ;  命令分隔符
        case 语句的分隔符要转义 ;;
    :空指令
    .  和source命令相同
    ~  家目录
    ,  分隔目录
    * 通配符
    ? 条件测试或通配符
    $ 取值符号
    | 管道符
    & 后台运行
       空格
测试和判断
退出程序命令
    exit 判断上一条命令是否正常,0或者非0
    exit 1或者0 返回10 给shell ,返回值非0位不正常退出
    $? 判断当前shell前一个进程是否正常退出

测试命令test

test命令用于检查文件或者比较值
test可以做以下测试
    文件测试 
    整数比较测试
    字符串测试

test测试语句可以简化为[]符号
    test -f /etc/passwd2 判断文件是否存在并且是个普通文件,-e是文件或者目录,-d目录
    [ -d /etc/ ]
[]符号还有扩展写法 [[]] 支持 && || < >
if
if-then 语句的基本用法
    if [ 测试条件成立 ] 或 命令返回值是否为0
    then 执行相应命令
    fi 结束

if-then-else 语句可以在条件不成立时也运行相应的命令
    if [ 测试条件成立 ]
    then 执行相应命令
    else 测试条件不成立,执行相应命令
    fi 结束

    if [ 测试条件成立 ]
    then 执行相应命令
    elif  [ 测试条件成立 ]
    then 执行相应命令
    else 测试条件不成立,执行相应命令
    fi 结束

嵌套 if 的使用
if 条件测试中可以再嵌套 if 条件测试
    if [ 测试条件成立 ]
    then 执行相应命令
        if [测试条件成立]
        then 执行相应命令
        fi
    fi
case
case 语句和 select 语句可以构成分支

case "$变量" in
    "情况1" )
    命令...;;;
    "情况2" )
    命令...;;;
    * )
     命令...;;;
esac
for
for 循环的语法
    for  参数 in 列表
    do 执行的命令
    done 封闭一个循环

使用反引号或 $() 方式执行命令,命令的结果当做列表进行处理
列表中包含多个变量,变量用空格分隔
    for i in {0..9}
    for filename in 'ls *.mp3'
对文本处理,要使用文本查看命令取出文本内容
默认逐行处理,如果文本出现空格会当做多行处理


C 语言风格的 for 命令
for((变量的初始化;循环判断条件;变量变化))
do
  命令
done
while
while test测试是否成立
do
    命令
done


until 循环 与while 循环相反,循环测试为假时,执行循环,为真实循环停止
break continue
break 退出
continue 结束本轮循环

使用循环处理位置参数

命令行参数可以使用 $1 $2 ... ${10}..$n 进行读取
$0 代表脚本名称
$* 和 $@ 代表所有位置参数
$# 代表位置参数的数量

有脚本test.sh如下:
#! /bin/bash

# help display help help

for pos in $*
do
        if [ "$pos" = "help"]; then
            echo $pos $pos
        fi
done

运行语句:
bash test.sh a b c help



while 脚本如下:

#! /bin/bash

while [ $# -ge 1]
do
        if [ "$1" = "help" ]; then
                echo $1 $1
        fi
        shift
done

shift能够参数左移
运行语句:
bash test.sh a b c help
自定义函数
函数用于“包含”重复使用的命令集合

自定义函数
    function fname(){
    命令
    }

函数的执行
    fname

函数作用范围的变量
local 变量名


函数的参数
$1 $2...$n

checkpid() {
    local i
    for i in $* ; do
        [ -d "/proc/$i" ] && return 0
    done
    return 1
}

执行时
checkpid 1    或者 checkpid 1 2
echo  $?
系统脚本
系统自建了函数库,可以在脚本中引用
/etc/init.d/functions

自建函数库
使用 source 函数脚本文件“导入”函数

source /etc/init.d/functions
echo_success
脚本优先级任务
可以使用 nice 和 renice 调整脚本优先级
避免出现“不可控的”死循环
死循环导致cpu占用过高
死循环导致死机

ulimit -a  可以查看当前终端的使用限制,root用户的话有些限制不会生效

max user processes 用户的最大进程数
任务计划
at 18:31
at > echo hello > /tmp/test.txt
at> 

然后ctrl +d 提交
cron
    配置方式
        crontab -e
    查看现有的计划任务
        crontab -l
    配置格式
        分钟,小时,日期,月份,星期,执行的命令
        注意命令的路径问题
    日志(可以查看计划任务有没有被执行)
        /var/log/cron
    每个用户都有自己的计划任务目录
        /var/spool/cron/用户

任务计划加锁

如果计算机不能按照预期时间运行
    anacontab 延时计划任务
    flock 锁文件
正则表达式和文本搜索
元字符

. 匹配除换行符外的任意单个字符
* 匹配任意一个跟在它前面的字符
[] 匹配方括号中的字符类中的任意一个
^ 匹配开头
$ 匹配结尾
\ 转义后面的特殊字符

扩展元字符
+ 匹配前面的正则表达式至少出现一次
? 匹配前面的正则表达式出现零次或一次
| 匹配它前面或后面的正则表达式


grep 搜索
grep test /root/test.txt
cd /etc
find passwd
    -regex 区分大小写
    -iregex 不区分大小写

find /etc -name pass*
find /etc -regex .*wd

类型匹配
find /etc -type f -regex .*wd
时间匹配,最基础的时间戳包括:-atime/-mtime/-ctime
find /etc/ -atime 8 -regex .*wd
删除.txt文件
find * txt -exec rm -v {} \;

Linux find命令常用用法示例

sed awk xargs
sed 的基本工作方式
 -将文件以行为单位读取到内存(模式空间)
 -使用sed的每个脚本对该行进行操作
 -处理完成后输出该行
sed 一般用于对文本内容做替换

    sed '/user1/s/user1/u1' /etc/passwd
    sed 's/old/new/' filename
    sed -e  's/old/new/' -e  's/old/new/' filename
    sed -i  's/old/new/' -i  's/old/new/' filename

    sed -r 's/(a*b)/\1 \1'  filename
    head -5 /etc/passwd | sed 's/...//'
    head -5 /etc/passwd | sed 's/s*sbin  //'
sed指令扩展
     s/old/new标志位
    数字.第几次出现才替换
    g,每次出现都进行替换
    p,打印模式空间的内容
    sed -n 阻止默认输出
    w file 将模式空间的内容写入到文件


sed 's/root/!!!/2' 
sed 's/root/!!!/g' 
sed -n 's/root/!!!/w  /tmp/a.txt'  

sed '1,3s/root/!!!/2'  第一行和第三行进行替换
sed '1,$s/root/!!!/2'  第一行到最后一行进行替换
寻址可以匹配多条命令
/regular/{ 's/old/new/' ; 's/old/new/'}
可以将选项保存为文件,使用-f加载脚本文件
sed -f sedscript filename
awk 基本用法
awk 一般用于对文本内容进行统计,按需要的格式进行输出
    cut 命令:cut -d:-f 1/etc/passwd
    awk 命令:awk -F: '/wd$/{print$1}' /etc/passwd
    
    awk '/^menu/{print $0}' /boot/grub2/grub.cfg 
    awk -F "'" '/^menu/{print $2}' /boot/grub2/grub.cfg
    awk -F "'" '/^menu/{print  x++, $2}' /boot/grub2/grub.cfg 
awk 表达式

系统变量
FS和OFS字段分隔符,OFS表示输出的字段分隔符
RS记录分隔符
NR FNR行数
NF字段数量,最后一个字段内容可以用$NF取出

 head -5 /etc/passwd | awk 'BEGIN{FS=":"}{print $1}'
 head -5 /etc/passwd | awk 'BEGIN{FS=":";OFS="---"}{print $1,$2}'
 head -5 /etc/passwd | awk '{print NR,$0}'
 awk '{print FNR,$0}'   /etc/passwd  /etc/passwd
 head -5 /etc/passwd | awk 'BEGIN{FS=":"}{print $NF}'

 awk '{if($2>80){print $1 ; print $2}}' kpi.txt
 head -1 kpi.txt | awk '{for(c=2;c<=NF;c++) print c}'
 head -1 kpi.txt | awk '{for(c=2;c<=NF;c++) print $c}'
xargs是将标准输入转为命令行参数
echo "a b c" | xargs mkdir
大多数情况下xargs命令都是跟着管道一起使用的
,但是,也可以单独使用,在输入xargs按下回车键,
命令行就会等待用户输入,作为标准输入,你可以输入
任意内容然后按下ctrl + d 表示输入结束,这时echo命令就会把前面的结果打印出来

-d指定分隔符
  echo -e "a\tb\tc" | xargs -d "\t" echo -n
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,240评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,328评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,182评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,121评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,135评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,093评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,013评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,854评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,295评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,513评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,398评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,989评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,636评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,657评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容