草庐IT

Shell脚本2

feizirui 2023-03-28 原文

前言

shell变量的类型:

  • 自定义变量:由用户自己定义,修改和使用
  • 环境变量:由系统维护,用于设置工作环境
  • 只读变量:只可以读取不可以更改
  • 位置变量:通过命令行给脚本传递参数
  • 预定义变量:Bash中内置的一类变量,不能修改 有些规定好的变量放在那里让你使用

补充:系统内置变量:PATH,UID,HOSTNAME,USER   

一、变量基础

1.1命名要求

  • 区分大小写
  • 不能使程序中的保留字和内置变量如:if, for,hostname 命令 a=
  • 只能使用数字、字母及下划线,且不能以数字开头,注意:不支持短横线 “ - ”,和主机名相反
  • 不要使用内置的变量,使用英文尽量使用词义通俗易懂,PATH
  • 大驼峰 StudentFirstName
  • 小驼峰 studentFirstName
  • 下划线 student_name

1.2定义变量

  • name='value' 【变量名=变量值】
  • $name(变量引用)
  • ${name}(变量引用)
  • 直接字串:name='root'
  • 变量引用:name="$USER"
  • 命令引用:name=`COMMAND` 或者 name=$(COMMAND)

注意:变量赋值是临时生效,当退出终端后,变量会自动删除,无法持久保存,脚本中的变量会随着脚本结束,也会自动删除

1.3弱引用和强引用

  • "$name " 弱引用:其中的变量引用会被替换为变量值
  • '$name ' 强引用:其中的变量引用不会被替换为变量值,而保持原字符串

补充:

  • 赋值时使用双引号(" ")可以直接调用变量
  • 赋值时使用单引号(' ')$只会被认为是字符$ 不会调用变量
  • 赋值时使用(``反撇在tab上面)命令替换,提取命令执行后的输出结 果$( ) 用法相同
  • {}可以分隔变量值
格式:变量名+=追加值
[root@server ~]#title=CTO
[root@server ~]#title+=feizirui
[root@server ~]#echo $title 

1.4read -p(从键盘输入的内容变成变量)

 

1.5变量作用范围

默认情况下,新定义的变量只在当前的shell环境中有效,因此称为局部变量,当进入子程序或新的shell环境中,局部变量将无法再起作用。可以通过内部命令export将指定的变量为全局变量,使用户定义的变量在所子shell环境中可以继续使用。
方法:

  • 格式1:export 变量名
  • 格式2:export 变量名=变量值

举例:

1.6整数的运算

expr只能进行整数的运算
格式: expr 变量1 运算符 变量2 [运算符 变量3]
运算符:
加法:+
减法:-
乘法:\ *
除法:/
取余(取模):%

1.7环境变量

环境变量:
可以使子进程(包括孙子进程)继承父进程的变量,但是无法让父进程使用子进程的变量
一旦子进程修改从父进程继承的变量,将会新的值传递给孙子进程
一般只在系统配置文件中使用,在脚本中较少使用

1. 由系统提前创建,用来设置用户的工作环境
2. 可以使用env查看环境变量
3. 需要记住的常用环境变量

  • $USER 表示用户名称
  • $HOME 表示用户的宿主目录
  • $LANG 表示语言和字符集
  • $PWD 表示当前所在工作目录
  • $PATH 表示可执行用户程序的默认路径

 

1.8环境变量的全局配置文件

配置文件位置在

  • /etc/profile:修改此文件会作用于所有用户
  • ~/.bash_profile:用户独立的配置文件,修改这个文件只作用于当前用户,可以用来长期变更或设置环境变量

 

1.9只读变量

变量值不允许修改(重新赋值)的情况,无法使用 unset删除,最快方法重启

1.10位置变量

位置变量也称为位置参数,使用$1、$2、$3、…、$9 表示

 

1.11预定义变量

系统帮你定义好了 拿来用就可以了,你不需要知道为什么,记住以下:

  • $*:表示所有位置参数的内容看成一个整体返回,返回所有 (45667) $1
  • $@:表示所有位置参数的内容分割成n份,每份作为一个独立的个体返回,返回所有 4 5 6 6 7
  • $?:表示前一条命令执行后的返回状态,返回值为 0 表示执行正确,返回任何非 0值均表示执行出现异常
  • $#:表示命令行中位置参数的总个数
  • $0:表示当前执行的脚本或程序的名称,当前脚本的名字
  • $$:当前进程id
  • $!:后台任务最后一个id

 

二、条件语句

2.1测试

  • 格式1:test 条件表达式
  • 格式2:[ 条件表达式 ],注意[]空格,否则会失败

2.2操作符

  • -d:测试是否为目录(Directory)
  • -e:测试目录或文件是否存在(Exist)
  • -a:测试目录或文件是否存在(Exist)
  • -f:测试是否为文件(File)
  • -r:测试当前用户是否有权限读取(Read)
  • -w:测试当前用户是否有权限写入(Write)
  • -x:测试当前用户是否有权限执行(eXcute)
  • -L:测试是否为软连接文件

2.3属性测试补充

  • -s FILE:#是否存在且非空
  • -t fd #:fd 文件描述符是否在某终端已经打开
  • -N FILE:#文件自从上一次被读取之后是否被修改过
  • -O FILE:#当前有效用户是否为文件属主
  • -G FILE:#当前有效用户是否为文件属组

条件测试:判断某需求是否满足,需要由测试机制来实现,专用的测试表达式需要由测试命令辅助完成
测试过程:实现评估布尔声明,以便用在条件性环境下进行执行

  • 若真,则状态码变量 $? 返回0
  • 若假,则状态码变量 $? 返回1
  • 条件测试命令

2.4比较整数数值

[ 整数1 操作符 整数2 ] 公式

  • -eq:第一个数等于(Equal)第二个数
  • -ne:第一个数不等于(Not Equal)第二个数
  • -gt:第一个数大于(Greater Than)第二个数
  • -lt:第一个数小于(Lesser Than)第二个数
  • -le:第一个数小于或等于(Lesser or Equal)第二个数
  • -ge:第一个数大于或等于(Greater or Equal)第二个数

2.5字符串比较

1、常用的测试操作符

  • =:字符串内容相同
  • !=:字符串内容不同,! 号表示相反的意思
  • -z:字符串内容为空
  • -n: 字符是否存在

2、格式:

  • [ 字符串1 = 字符串2 ] 是否相同
  • [ 字符串1 != 字符串2 ] 是否不相同
  • [ -z 字符串 ] 是否为空
  • [ -n 字符串 ] 字符是否存在

2.6逻辑测试(短路运算)

  • 格式1:[ 表达式1 ] 操作符 [ 表达式2 ] ...
  • 格式2:命令1 操作符 命令2 ...

常见条件:

  • -a或&&:逻辑与,“而且”的意思全真才为真
  • -o或||:逻辑或,“或者”的意思一真即为真
  • !:逻辑否

(1)短路与 &&

1 CMD1 短路与 CMD2:&&同时满足命令1和命令2 的要求,才会返回正确
2 全真才为真,一假即为假   
3 第一个CMD1结果为真 ,第二个CMD2必须要参与运算,才能得到最终的结果 
4 第一个CMD1结果为假 ,总的结果必定为假,因此不需要执行CMD2

(2)短路或 ||

1 CMD1 短路或 CMD2
2 一真即为真
3 第一个CMD1结果为真 (1),总的结果必定为1,因此不需要执行CMD2
4 第一个CMD1结果为假 (0),第二个CMD2 必须要参与运算,才能得到最终的结果

1 ping 小脚本
2 -c 发送包的个数
3 -i 发送的间隔时间
4 -W 超时时间
5 -w 多少秒后停止ping操作

 

三、if语句分支结构

3.1if介绍

       

单分支结构:

if 判断条件;

then   条件为真的分支代码

fi
双分支结构:

if 判断条件; then
 条件为真的分支代码

else
 条件为假的分支代码

fi
多分支结构:

if 判断条件1
then
 条件1为真的分支代码

elif 判断条件2
then
 条件2为真的分支代码

elif 判断条件3;then
 条件3为真的分支代码

...
else
 以上条件都为假的分支代码

fi

例1:

例2:

例3:

3.2case

格式:
case 变量引用 in
PAT1)
 分支1
 ;;
PAT2)
 分支2
 ;;
...
*)
 默认分支
 ;;

case支持glob风格的通配符:

  • * 任意长度任意字符
  • ? 任意单个字符
  • [0-9] 指定范围内的任意单个字符
  • |表示:或者意思,如: a|b

例1:

 例2:

 

3.3echo

echo -n:表示不换行输出
echo -e:表示输出转义符

data日期命令:

  • date:查看当前系统时间
  • -d :你描述的日期,显示指定字符串所描述的时间,而非当前时间
  • %F:完整日期格式,等价于 %Y-%m-%d
  • %T:时间(24小时制)(hh:mm:ss)

四、循环语句

4.1for循环

循环含义:将某代码段重复运行多次,通常有进入循环的条件和退出循环的条件
常见的循环的命令:for, while, until

执行机制:
依次将列表中的元素赋值给“变量名”; 每次赋值后即执行一次循环体; 直到列表中的元素耗尽,循环结束;
如果省略 [in WORDS ... ] ,此时使用位置参数变量 in "$@" for (( 表达式1; 表达式2; 表达式3 )); do 命令; done

 例1:

方法一:

 

方法二:

 方法三:

4.2while和until

相对于for,需要知道循环次数,我们只知道停止条件,不知道次数,就需要使用while,直到达到条件

while:当命令判断为假时停止
until:当命令判断为真时停止

双重循环及跳出循环:

  • break跳出单个循环后面加数字2则代表跳出两层循环
  • continue终止某次循环中的命令,但是不会完全终止命令

例1:

例2:

 

4.3select 菜单选择

PS1 提示符
PS2 多行重定向
PS3 菜单选择

 例1:

有关Shell脚本2的更多相关文章

  1. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  2. ruby-on-rails - 独立 ruby​​ 脚本的配置文件 - 2

    我有一个在Linux服务器上运行的ruby​​脚本。它不使用rails或任何东西。它基本上是一个命令行ruby​​脚本,可以像这样传递参数:./ruby_script.rbarg1arg2如何将参数抽象到配置文件(例如yaml文件或其他文件)中?您能否举例说明如何做到这一点?提前谢谢你。 最佳答案 首先,您可以运行一个写入YAML配置文件的独立脚本:require"yaml"File.write("path_to_yaml_file",[arg1,arg2].to_yaml)然后,在您的应用中阅读它:require"yaml"arg

  3. ruby-on-rails - 如何在 ruby​​ 交互式 shell 中有多行? - 2

    这可能是个愚蠢的问题。但是,我是一个新手......你怎么能在交互式ruby​​shell中有多行代码?好像你只能有一条长线。按回车键运行代码。无论如何我可以在不运行代码的情况下跳到下一行吗?再次抱歉,如果这是一个愚蠢的问题。谢谢。 最佳答案 这是一个例子:2.1.2:053>a=1=>12.1.2:054>b=2=>22.1.2:055>a+b=>32.1.2:056>ifa>b#Thecode‘if..."startsthedefinitionoftheconditionalstatement.2.1.2:057?>puts"f

  4. postman——集合——执行集合——测试脚本——pm对象简单示例02 - 2

    //1.验证返回状态码是否是200pm.test("Statuscodeis200",function(){pm.response.to.have.status(200);});//2.验证返回body内是否含有某个值pm.test("Bodymatchesstring",function(){pm.expect(pm.response.text()).to.include("string_you_want_to_search");});//3.验证某个返回值是否是100pm.test("Yourtestname",function(){varjsonData=pm.response.json

  5. ruby-on-rails - rbenv:从 RVM 移动到 rbenv 后,在 Jenkins 执行 shell 中找不到命令 - 2

    我从Ubuntu服务器上的RVM转移到rbenv。当我使用RVM时,使用bundle没有问题。转移到rbenv后,我在Jenkins的执行shell中收到“找不到命令”错误。我内爆并删除了RVM,并从~/.bashrc'中删除了所有与RVM相关的行。使用后我仍然收到此错误:rvmimploderm~/.rvm-rfrm~/.rvmrcgeminstallbundlerecho'exportPATH="$HOME/.rbenv/bin:$PATH"'>>~/.bashrcecho'eval"$(rbenvinit-)"'>>~/.bashrc.~/.bashrcrbenvversions

  6. ruby - 确定 ruby​​ 脚本是否已经在运行 - 2

    有没有一种简单的方法可以判断ruby​​脚本是否已经在运行,然后适本地处理它?例如:我有一个名为really_long_script.rb的脚本。我让它每5分钟运行一次。当它运行时,我想看看之前运行的是否还在运行,然后停止第二个脚本的执行。有什么想法吗? 最佳答案 ps是一种非常糟糕的方法,并且可能会出现竞争条件。传统的Unix/Linux方法是将PID写入文件(通常在/var/run中)并在启动时检查该文件是否存在。例如pid文件位于/var/run/myscript.pid然后你会在运行程序之前检查它是否存在。有一些技巧可以避免

  7. ruby - 从 Ruby : capturing the output while displaying the output? 运行 shell 命令 - 2

    我有一个问题。我想从另一个ruby​​脚本运行一个ruby​​脚本并捕获它的输出信息,同时让它也输出到屏幕。亚军#!/usr/bin/envrubyprint"Enteryourpassword:"password=gets.chompputs"Hereisyourpassword:#{password}"我运行的脚本文件:开始.rboutput=`runner`putsoutput.match(/Hereisyour(password:.*)/).captures[0].to_s正如您在此处看到的那样,存在问题。在start.rb的第一行,屏幕是空的。我在运行程序中看不到“输入您的密

  8. ruby - ruby 脚本可以预编译成二进制文件吗? - 2

    我正在开发一个Ruby脚本,需要在没有Ruby解释器的情况下部署到系统上。它将需要在使用ELF格式的FreeBSD系统上运行。我知道有一个ruby​​2exe项目可以编译在Windows上运行的ruby​​脚本,但是在其他操作系统上这样做容易吗?甚至可能吗? 最佳答案 您是否检查过Rubinius或JRuby是否允许您预编译您的代码? 关于ruby-ruby脚本可以预编译成二进制文件吗?,我们在StackOverflow上找到一个类似的问题: https://

  9. ruby - 可以正常中断的来自 Rake 的长时间运行的 shell 命令? - 2

    在几个项目中,我希望有一个类似rakeserver的rake任务,它将通过任何需要的方式开始为该应用程序提供服务。这是一个示例:task:serverdo%x{bundleexecrackup-p1234}end这行得通,但是当我准备停止它时,按Ctrl+c并没有正常关闭;它中断了Rake任务本身,它说rakeaborted!并给出堆栈跟踪。在某些情况下,我必须执行Ctrl+c两次。我可能可以用Signal.trap写一些东西来更优雅地中断它。有没有更简单的方法? 最佳答案 trap('SIGINT'){puts"Yourmessa

  10. ruby-on-rails - Ruby 从 bash 脚本执行中捕获 stderr 输出 - 2

    我目前可以将stdout重定向到ruby​​/rails中的字符串变量,只需在bash中运行命令并将结果设置为我的字符串变量,如下所示。val=%x[#{cmd}]其中cmd是表示bash命令的字符串。但是,这仅捕获stdout,因为我想捕获stderr并将其设置为ruby​​中的字符串——有什么想法吗? 最佳答案 简单地重定向它:val=%x[#{cmd}2>&1]如果您只想从stderr捕获输出,请在将其复制到fd2后关闭stdout的文件描述符。val=%x[#{cmd}2>&1>/dev/null]

随机推荐