Shell脚本学习
shell脚本和Linux的联系
linux命令其实背后应该是一些C语言的代码,当我们在命令行中输入ls 这种命令的时候,其实是执行了一段C语言的代码, 这些内容是存储在bin目录下。
shell是一种解释器,可以理解为包裹着操作系统的壳。当用户输入了一条Linux命令后,通过shell来进行解释。
Shebang
Shebang 目的是指定相应的解释器,shebang是#! ,默认是sh执行的,
还存在bash、csh、zsh、tcsh、或者指定python、c
当需要使用bash解释器解释shell代码的时候需要指定shebang为 #!/bin/bash,使用python解释器的时候shebang指定为 #!/bin/python
一个shell脚本,如果直接使用绝对路径执行,是不成立的,因为使用绝对路径的时候会在PATH变量下进行寻找,所以应该使用相对路径执行。
Shell 变量
shell 是一种非强类型的语言,也就是说定义变量的时候不需要声明变量类型。直接使用 var Name = “变量值”。使用单引号和双引号是有区别的,单引号不能识别特殊字符,双引号可以识别特殊字符。
在已经开启了一个shell的时候可以通过bash、zsh这种命令进入到新的shell中,shell切换会导致变量丢失。可以通过pstree查看父子shell的关系。退出shell的时候使用exit方法。
本地变量是只针对当前的shell环境存在。所以在切换shell得时候会丢失相关的shell。
环境变量是针对所有的shell环境存在,所以在切换shell的时候也可以读取到相应的变量。
特殊变量
$?,这个值返回的是一个状态码,可以用来判断上一条语句是否执行成功了,如果返回的结果是0的话,则证明执行成功,失败的会会有不同错误对应的不同状态码 $0 获取shell脚本文件名以及路径 $n 获取shell脚本第n个参数,在1~9之间,大于9要写${10} $# 获取执行shell脚本后的总参数 $*/$@ 获取所有参数,不加引号相当于$@ 在$*/$@ 不被引号包围的时候是一样的,都是获取所有参数,将参数作为一整段字符处理的,但是当它被引号包围的时候,$*仍然是处理成一段字符,而$@是通过循环的模式,一个一个参数的输出。
当我们想要使用某个变量接受Linux命令返回的结果时,直接使用 name='ls';是不可以的,需要使用反引号进行说明
zhaozexin@zhaozexins-MacBook-Pro ~/IdeaProjects/shell_practice name=`ls` ✔ 3039 14:50:05 zhaozexin@zhaozexins-MacBook-Pro ~/IdeaProjects/shell_practice echo $name ✔ 3040 15:11:17 hello.sh zhaozexin@zhaozexins-MacBook-Pro ~/IdeaProjects/shell_practice
执行shell脚本的时候,如果使用source命令或者.命令执行的时候会使用当前的解释器执行,如果使用其他解释器,例如bash或者zsh或者sh 执行shell文件的时候,会打开一个子shell。
特殊状态变量
$? 返回状态码,0是成功,其他是不同的失败状态码 $$ 获取当前脚本执行的pid $! 获取上一次后台执行进程的PID,想要让某程序后台运行可以使用nohup 命令
环境变量设置
环境变量一般情况都会设置在配置文件中,个人配置文件有 ~./bash_profile, ~./bashrc, 全局的配置文件是etc/profile 和 etc/bashrc
使用set 命令可以找到当前shell中的全部变量,包括全局变量和局部变量
env命令只能找出全局变量
declare可以找出所有的变量和set命令相同
export 显示和设置环境变量值
取消变量使用 unset 变量名,删除变量或者函数
shell变量加载顺序
-
ssh登陆Linux以后,系统启动一个bash shell, bash会读取若干系统环境文件,检查环境变量设置
-
首先执行全局的etc/profile,为系统的每个用户设置环境信息
-
然后读取etc/profile.d目录下的脚本,有系统诸多脚本也放入自定义需要登陆加载的脚本,便于用于登陆后立即运行脚本
-
运行$HOME/.bash_profile(用户环境变量文件)
-
运行$HOME/.bashrc
-
运行etc/.bashrc
bash中的内置命令
echo -n参数表示不换行 -e参数表示可以解析特殊字符 和 printf 效果一样 eval 可以执行多个命令 exec 不创建子进程,执行后续命令,执行完毕后会自动exit export read
shell子串中的基本用法
${变量} 取出对应的变量 ${#变量} 计算对应变量的长度 ${变量:start} 取出start下标后的变量 ${变量:start:length} 取出start下标后长度为length的变量 ${变量#word} 删除从头开始匹配到word字符的最短字符 ${变量##word} 删除从头开始匹配到word字符的最长字符 ${变量%word} 删除从尾开始匹配到word字符的最短字符 ${变量%%word} 删除从尾开始匹配到word字符的最长字符 zhaozexin@zhaozexins-MacBook-Pro ~/IdeaProjects/shell_practice echo $name ✔ 3036 16:04:53 zhaozexin@zhaozexins-MacBook-Pro ~/IdeaProjects/shell_practice name="zhaozexinhenshuai" ✔ 3066 16:27:37 zhaozexin@zhaozexins-MacBook-Pro ~/IdeaProjects/shell_practice echo ${name} ✔ 3067 16:27:55 zhaozexinhenshuai zhaozexin@zhaozexins-MacBook-Pro ~/IdeaProjects/shell_practice echo ${#name} ✔ 3068 16:28:06 17 zhaozexin@zhaozexins-MacBook-Pro ~/IdeaProjects/shell_practice echo ${name:4} ✔ 3069 16:28:20 zexinhenshuai zhaozexin@zhaozexins-MacBook-Pro ~/IdeaProjects/shell_practice echo ${name:4:5} ✔ 3070 16:30:07 zexin zhaozexin@zhaozexins-MacBook-Pro ~/IdeaProjects/shell_practice echo ${name#zhao} ✔ 3071 16:30:38 zexinhenshuai zhaozexin@zhaozexins-MacBook-Pro ~/IdeaProjects/shell_practice echo ${name##ze} ✔ 3072 16:30:56 zhaozexinhenshuai zhaozexin@zhaozexins-MacBook-Pro ~/IdeaProjects/shell_practice echo ${name%hen} ✔ 3073 16:31:18 zhaozexinhenshuai
统计命令执行时长
使用time命令可以统计时长。统计长度的命令有 ${#变量}、 ${变量} |wc -L、expr length。 其中 ${#变量}的执行效率最高,在shell中尽量使用内置函数,这些的速度是最快的,尽量避免使用管道符,管道符是上一个命令执行完毕后传递给下一个命令,所以会速度比较慢。
批量修改文件名
测试数据准备 zhaozexin@zhaozexins-MacBook-Pro ~/IdeaProjects/shell_practice mkdir sub_str ✔ 3084 16:55:22 zhaozexin@zhaozexins-MacBook-Pro ~/IdeaProjects/shell_practice cd sub_str ✔ 3085 16:55:35 zhaozexin@zhaozexins-MacBook-Pro ~/IdeaProjects/shell_practice/sub_str touch zexin_{1..5}_finished.jpg zhaozexin@zhaozexins-MacBook-Pro ~/IdeaProjects/shell_practice/sub_str touch zexin_{1..5}_finished.png zhaozexin@zhaozexins-MacBook-Pro ~/IdeaProjects/shell_practice/sub_str ls ✔ 3088 16:56:22 zexin_1_finished.jpg zexin_2_finished.jpg zexin_3_finished.jpg zexin_4_finished.jpg zexin_5_finished.jpg zexin_1_finished.png zexin_2_finished.png zexin_3_finished.png zexin_4_finished.png zexin_5_finished.png zhaozexin@zhaozexins-MacBook-Pro ~/IdeaProjects/shell_practice/sub_str ls -l ✔ 3089 16:56:25 total 0 -rw-r--r-- 1 zhaozexin staff 0 Aug 2 16:56 zexin_1_finished.jpg -rw-r--r-- 1 zhaozexin staff 0 Aug 2 16:56 zexin_1_finished.png -rw-r--r-- 1 zhaozexin staff 0 Aug 2 16:56 zexin_2_finished.jpg -rw-r--r-- 1 zhaozexin staff 0 Aug 2 16:56 zexin_2_finished.png -rw-r--r-- 1 zhaozexin staff 0 Aug 2 16:56 zexin_3_finished.jpg -rw-r--r-- 1 zhaozexin staff 0 Aug 2 16:56 zexin_3_finished.png -rw-r--r-- 1 zhaozexin staff 0 Aug 2 16:56 zexin_4_finished.jpg -rw-r--r-- 1 zhaozexin staff 0 Aug 2 16:56 zexin_4_finished.png -rw-r--r-- 1 zhaozexin staff 0 Aug 2 16:56 zexin_5_finished.jpg -rw-r--r-- 1 zhaozexin staff 0 Aug 2 16:56 zexin_5_finished.png 批量修改的脚本 for file_name in `ls *fin*jpg`;do mv $file_name `echo ${file_name//_finished/}`;done
怎么检测在子shell中
bash中有一个原生有的变量 BASH_SUBSHELL,当这个值为0的时候证明执行这条语句的时候没有创建子shell。这里有一个概念是使用进程列表的时候会开启子进程,括号是shell的特殊语法,每一层括号都会开启一个子shell。(pwd;ls;(echo $BASH_SUBSHELL))
在shell脚本的开发中我们经常使用子shell进行多线程的处理,提高程序并发执行的效率。
内置命令和外置命令
内置命令是始终在内存中的,不需要额外从磁盘中获取,所以内置命令的执行速度一般都比较快;外置命令是需要在磁盘中加载到内存再执行的。
查看某个命令是不是内置命令可以使用type命令
zhaozexin@zhaozexins-MacBook-Pro ~ type cd ✔ 3105 20:43:05 cd is a shell builtin
查看所有内置命令可以使用 compgen -b