首页 > 系统相关 >shell 编程基础

shell 编程基础

时间:2023-02-02 17:45:18浏览次数:64  
标签:shell string name 编程 基础 echo substring var 变量

变量类型

Shell中按照变量的作用域和生命周期,Shell变量可分为四大类:

(1)永久环境变量:需要修改配置文件,变量永久生效。

(2)临时环境变量:使用export命令行声明即可,变量在Shell脚本进程结束后仍然有效,但在关闭当前Shell会话后失效。

(3)全局变量:在脚本中定义,仅在当前Shell脚本中有效,其他Shell脚本进程不能访问,其作用域从定义的位置开始,到脚本结束或被显示删除的地方为止。注意,全局变量既可以在Shell函数内定义,也可以在Shell函数外定义,因为Shell函数内定义的变量默认为global,且作用域从“函数被调用时执行变量定义的地方”开始,到脚本结束或被显示删除的地方为止。

#!/bin/bash
 
global globalVar=dablel   #全局变量

(4)局部变量。在Shell脚本中函数内显示使用local关键字定义的变量。其作用域局限于函数内。同名local变量会屏蔽global变量。

#!/bin/bash

functiontest()
{
local localVar=dablel  #局部变量
}
test
echo ${localVar}             #输出为空

 

定义变量

Shell 支持以下三种定义变量的方式:

var=value
var='value'
var="value"

#举便如下:
name='dablelv'
home="安徽"
age=28


var是变量名,value是赋给变量的值。如果value不包含任何空白符(例如空格、Tab等),那么可以不使用引号;如果value 包含了空白符,那么就必须使用引号包围起来。使用单引号和使用双引号也是有区别的,稍后我们会详细说明。注意,赋值号的周围不能有空格,这可能和你熟悉的大部分编程语言都不一样。

Shell变量的命名规范和大部分编程语言都一样:
(1)变量名由数字、字母、下划线组成;
(2)必须以字母或者下划线开头;
(3)不能使用Shell里的关键字(通过help命令可以查看保留关键字)。

访问变量

 

使用一个定义过的变量,只要在变量名前面加美元符号$即可,如:

name="dablelv"
echo $name
echo ${name}

 

变量名外面的花括号{}是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,比如下面这种情况:

skill="Java"

echo"I am good at ${skill}Script"

如果不给skill变量加花括号,解释器就会把$skillScript当成一个变量(其值为空),代码执行结果就不是我们期望的样子了。

推荐给所有变量加上花括号{ },这是个良好的编程习惯

单引号和双引号的区别

定义变量时,变量的值可以由单引号包围,也可以由双引号包围,它们到底有什么区别呢?

#!/bin/bash
 
name='dablelv'
str1='我的名字是${name}'
str2="我的名字是${name}"
echo $str1
echo $str2

运行结果:

我的名字是${name}
我的名字是dablelv

以单引号包围变量的值时,单引号里面是什么就输出什么,即使内容中有变量和命令(命令需要反引起来)也会把它们原样输出。这种方式比较适合定义显示纯字符串的情况,即不希望解析变量、命令等的场景。

以双引号包围变量的值时,输出时会先解析里面的变量和命令,而不是把双引号中的变量名和命令原样输出。这种方式比较适合字符串中附带有变量和命令并且想将其解析后再输出的变量定义。

建议:如果变量的内容是数字,那么可以不加引号;如果真的需要原样输出就加单引号;其他没有特别要求的字符串等最好都加上双引号,定义变量时加双引号是最常见的使用场景。

 

将命令的结果赋值给变量

Shell 也支持将命令的执行结果赋值给变量,常见的有以下两种方式:

variable=`command`
variable=$(command)

第一种方式把命令用反引号包围起来,反引号和单引号非常相似,容易产生混淆,所以不推荐使用这种方式;第二种方式把命令用$()包围起来,区分更加明显,所以推荐使用这种方式。

例如将两个数值相加赋给某一变量。

var1=1
var2=2
varAdd1=`expr $var1 + $var2`
varAdd2=$(expr $var1 + $var2)

只读变量

使用readonly命令,或者使用declare -r或typeset -r可以将变量定义为只读变量,只读变量的值不能被改变。

name="dablelv"
readonly name
 
declare -r name="dablelv"
 
typeset -r name="dablelv"

删除变量

使用unset内置命令可以删除变量。语法:

	
unset variable_name

 

unset命令不能删除只读变量。变量被删除后不能再次使用。如

#!/bin/bash
 
name="dablelv"
unset name
echo $name

上面的脚本没有任何输出。

 

系统变量

$0:当前程序的名称;

$n:当前系统的第n个参数,n=1,2,3,4,5,6,7,8,9

$*:当前参数的所有参数(不含程序本身)

$# 当前程序的参数个数(不包括程序本身)

$?:命令或者程序执行后的状态,返回0表示成功;这里跟我们常识感觉可能不一样,因为我们一般以0为无,没有的意思;通常认为0表示失败,这里恰恰相反,大家注意;

$UID:当前用户的ID;

$PWD:当前所在的目录;(这里的PWD不是密码的意思,不是表示password,而是print working directory,一般英语大写缩写都是多个单词的缩写,这里注意,容易误解);

 

变量名

函数

$FUNCNAME

函数名称

$RANDOM

随机数

${BASH_REMATCH[@]}

匹配正则表达式的列表

$0

脚本名称

$1~$n

脚本位置参数,10及以上表示为${10},shift进行偏移获取参数值

$@

所有位置参数(列表),无论是否加上双引号,每个位置的参数都被当作一个独立的单词来处理

$*

所有位置参数(字符串),使用 $* 时,如果加上双引号,即 "$* " 的形式,那所有位置的参数会被当作一个单词来处理,如果不包含双引号,即 $* 的形式,则每个位置的参数都被当作一个独立的单词来处理

$#

位置参数的个数

$_

上一条命令最后一个参数

$?

上条命令的返回值,获取执行上一个指令的执行状态返回值(0为成功,非零为失败)

$$

脚本的PID

$PPID

父进程ID

$LINENO

脚本执行的行号

$PWD

当前目录

$SECONDS

脚本已经运行的时间(s)

$TMOUT

超时退出时间(s)

$UID

当前用户ID

$HOME

用户home目录

$GROUPS

当前用户组ID

$IFS

此变量用于 Bash 识别字符串或单词边界,默认值是空格,脚本中根据需要可以修改此变量的值

当 $IFS 为 : 时,字符串 "a:b:c"被解析成 a b c

当 $IFS 为 - 时,字符串 "x-y-z"被解析成 x y z

当 $IFS 为 , 时,字符串 "e,f,g"被解析成 e f g

现有#!/bin/bash cnt=1 echo 'test 1111' for var in "$*" do echo "arg$cnt="$var let "cnt+=1" done echo cnt=1 echo 'test 2222' for var in $* do echo "arg$cnt="$var let "cnt+=1" done echo cnt=1 echo 'test 3333' for var in "$@" do echo "arg$cnt="$var let "cnt+=1" done echo cnt=1 echo "test 4444" for var in $@ do echo "arg$cnt="$var let "cnt+=1" done


执行 ./c.sh 1 2 3,结果如下:

[root@ecs-centos-7 ~]# ./c.sh 1 2 3
test 1111
arg1=1 2 3

test 2222
arg1=1
arg2=2
arg3=3

test 3333
arg1=1
arg2=2
arg3=3

test 4444
arg1=1
arg2=2
arg3=3

从上面的结果可以看出,对于 $* 来说,加了双引号之后所有位置参数就会被视为一个单词

对于 $@ 来说,是否加双引号,结果都是一样的

所以,仅在使用双引号时,$*和 $@ 才会有差异

 

执行结果输入输出

command > file 将输出重定向到 file。
command < file 将输入重定向到 file。
command >> file 将输出以追加的方式重定向到 file。
n > file 将文件描述符为 n 的文件重定向到 file。
n >> file 将文件描述符为 n 的文件以追加的方式重定向到 file。
n >& m 将输出文件 m 和 n 合并。
n <& m 将输入文件 m 和 n 合并。
<< tag 将开始标记 tag 和结束标记 tag 之间的内容作为输入。

$ command > /dev/null
/dev/null 是一个特殊的文件,写入到它的内容都会被丢弃;如果尝试从该文件读取内容,那么什么也读不到。但是 /dev/null 文件非常有用,将命令的输出重定向到它,会起到"禁止输出"的效果。
如果希望屏蔽 stdout 和 $ command > /dev/null 2>&1

二元比较

-eq    等于
=       等于
==     等于
-ne   不等于
!=     不等于
-lt     小于
<     小于 (ASCII) *
-le    小于等于
-gt    大于
>    大于 (ASCII) *
-ge     大于等于
-z    字符串为空
-n    字符串不为空

> 大于
>= 大于等于
< 小于
<= 小于等于

 

文件测试类型

-e 文件是否存在
-s 文件大小不为0
-f 是一个标准文件
-d 是一个目录
-r 文件具有读权限
-w 文件具有写权限
-x 文件具有执行权限
-h 文件是一个符号链接
-L 文件是一个符号链接
-b 文件是一个块设备
-c 文件是一个字符设备
-g 设置了sgid标记
-p 文件是一个管道
-u 设置了suid标记
-S 文件是一个socket
-k 设置了"粘贴位"
-t 文件与一个终端相关联
-N 从这个文件最后一次被读取之后, 它被修改过
-O 这个文件的宿主是你
-G 文件的组id与你所属的组相同
F1 -nt F2 文件F1比文件F2新 *
F1 -ot F2 文件F1比文件F2旧 *
F1 -ef F2 文件F1和文件F2都是同一个文件的硬链接 *

! "非" (反转上边的测试结果)

 

参数替换和扩展

表达式 含义
${var} 变量var的 值, 与$var相同

${var-DEFAULT} 如果var没 有被声明, 那么就以$DEFAULT作为其值 *
${var:-DEFAULT} 如果var没 有被声明, 或者其值为空, 那么就以$DEFAULT作为其值 *

${var=DEFAULT} 如果var没 有被声明, 那么就以$DEFAULT作为其值 *
${var:=DEFAULT} 如果var没 有被声明, 或者其值为空, 那么就以$DEFAULT作为其值 *

${var+OTHER} 如果var声 明了, 那么其值就是$OTHER, 否则就为null字符串
${var:+OTHER} 如 果var被设置了, 那么其值就是$OTHER, 否则就为null字符串

${var?ERR_MSG} 如果var没 被声明, 那么就打印$ERR_MSG *
${var:?ERR_MSG} 如果var没 被设置, 那么就打印$ERR_MSG *

${!varprefix*} 匹配之前所有以varprefix开头进行声明的变量
${!varprefix@} 匹配之前所有以varprefix开头进行声明的变量

${#string} $string的 长度

${string:position} 在$string中, 从位置$position开始提取子串
${string:position:length} 在$string中, 从位置$position开始提取长度为$length的子串

${string#substring} 从 变量$string的开头, 删除最短匹配$substring的子串
${string##substring} 从 变量$string的开头, 删除最长匹配$substring的子串
${string%substring} 从 变量$string的结尾, 删除最短匹配$substring的子串
${string%%substring} 从 变量$string的结尾, 删除最长匹配$substring的子串

${string/substring/replacement} 使用$replacement, 来代替第一个匹配的$substring
${string//substring/replacement} 使 用$replacement, 代替所有匹配的$substring
${string/#substring/replacement} 如 果$string的前缀匹配$substring, 那么就用$replacement来代替匹配到的$substring
${string/%substring/replacement} 如果$string的后缀匹配$substring, 那么就用$replacement来代替匹配到的$substring


expr match "$string" '$substring' 匹配$string开头的$substring* 的长度
expr "$string" : '$substring' 匹 配$string开头的$substring* 的长度
expr index "$string" $substring 在$string中匹配到的$substring的第一个字符出现的位置
expr substr $string $position $length 在$string中 从位置$position开始提取长度为$length的子串
expr match "$string" '\($substring\)' 从$string的 开头位置提取$substring*
expr "$string" : '\($substring\)' 从$string的 开头位置提取$substring*
expr match "$string" '.*\($substring\)' 从$string的 结尾提取$substring*
expr "$string" : '.*\($substring\)' 从$string的 结尾提取$substring*

 

中括号

if [ CONDITION ] 测 试结构
if [[ CONDITION ]] 扩 展的测试结构
Array[1]=element1 数 组初始化
[a-z] 正 则表达式的字符范围

 

大括号

${variable} 参数替换
${!variable} 间 接变量引用
{ command1; command2; . . . commandN; } 代码块
{string1,string2,string3,...} 大 括号扩展

 

圆括号

( command1; command2 ) 子shell中 执行的命令组
Array=(element1 element2 element3) 数组初始化
result=$(COMMAND) 在 子shell中执行命令, 并将结果赋值给变量
>(COMMAND) 进 程替换
<(COMMAND) 进 程替换

 

双圆括号

(( var = 78 )) 整型运算
var=$(( 20 + 5 )) 整型运算, 并将结果赋值给变量

 

后置引用

result=`COMMAND` 在 子shell中运行命令, 并将结果赋值给变量

标签:shell,string,name,编程,基础,echo,substring,var,变量
From: https://www.cnblogs.com/pandaly/p/17086811.html

相关文章

  • 场景编程集锦 - 银行柜员现金清分
    1.场景描述  跨界一词不知道什么时候成为了热词。电影演员学说相声,跨界表演展现多才多艺的才能;县长直播带货,推荐地方土特产,展现即兴表演才能;退役核潜艇艇长担任银行电......
  • Java基础学习10--算法
     队列(2023-02-02)使用数组模拟队列(未优化)1.需要用的变量有front=-1,rear=-1,maxsize以及数组int[]arr;2.判断队列已满的条件是rear==maxsize-1,队列为空的条件是rear==fro......
  • vim基础用法
    如何退出Esc+:q(或者:wq,如果你改了东西要保存的话;:!q不保存,强制退出)讲个笑话:我用vim三年了,因为我到现在都不知道怎么退出!删除所有内容Esc+ggdG跳转到指定行E......
  • 2、Python基础(函数)
    #格式化代码快捷键Ctrl+Alt+L#函数的定义​deff1():print("你好")​​#函数的调用f1()​​#函数的参数#使用函数计算1+2的值​d......
  • 基础
    泛型工具Required将类型的属性变成必选interfacePerson{name?:string;age?:number;hobby?:string[];}typeRequired<T>={[KeyinkeyofT]-?:T[......
  • 数据库:事务基础知识
    事务概述存储引擎支持情况可以使用SHOWENGINES命令查看Mysql支持事务的存储引擎有哪些。Mysql中只有InnoDB支持事务。基本概念事务:一组逻辑操作单元,使数据从一种状......
  • pandas 基础
    安装及导入安装可以使用pip安装pipinstallpandas导入importpandasaspd数据结构SeriesSeries是一种类似于一维数组的对象,它由一组数据(各种Numpy数据类......
  • Java基础-浅拷贝和深拷贝
    浅拷贝浅拷贝会在堆上创建一个新的对象,如果原对象的属性是一个引用类型,拷贝的内部对象是原对象内部对象的引用地址,即原对象和拷贝对象用的是同一个内部对象。classInner......
  • 通过Jenkins在远程服务器上执行shell脚本
    1、Jenkins安装PublishoverSSH插件         下载安装PublishoverSSH插件 2、配置服务器相关信息    要先在jenkins所在的机器上生成秘......
  • 《区块链基础知识25讲》-第六讲-所有权
    区块链可以用来管理和区分所有权所有权证明三要素对所有者的证明对事物被拥有的证明提供一个所有者与事物之间的连接区块链是一个能够被任何人访问,拥有类似账本功能的巨大去......