1. 变量相关知识

1. 变量相关知识

  • 静态编译语言:使用变量前,先声明变量类型,之后类型不能改变,在编译时检查,如:java,c
  • 动态编译语言:不用事先声明,可随时改变类型,如bash,Python
  • 强类型语言:不同类型数据操作,必须经过强制转换才同一类型才能运算,如java , c# ,python
    • 如:以下python代码
      print(‘magedu’+ 10) 提示出错,不会自动转换类 型
      print(‘magedu’+str(10)) 结果为magedu10,需要显示转 换类型
  • 弱类型语言:语言的运行时会隐式做数据类型转换。无须指定类型,默认均为字符型;参与运算会自动进行隐式类型转换;变量无须事先定义可直接调用
    如:bash 不支持浮点数,php,javascript

2. 变量基本概念

  • 变量:命名的内存空间
  • 变量:变量类型 作用:
  1. 数据存储方式
  2. 参与的运算
  3. 表示的数据范围
    类型:
    字符型
    数值型:整型、浮点型(注意bash shell只能整型,不能处理浮点型)

3. Shell中变量命名法则:

  1. 不能使程序中的保留字:例如if, for
  2. 只能使用数字、字母及下划线,且不能以数字开头
  3. 见名知义
  4. 统一命名规则:驼峰命名法 :利用下划线或者每个名称开头都大写等等

3.1. Shell中命名建议规则:

  1. 变量名大写
  2. 局部变量小写
  3. 函数名小写
  4. 用英文名字,并体现出实际作用

4. bash中变量的种类—{特殊变量$}

  • 根据变量的生效范围等标准划分下面变量类型
  1. 局部变量(bash默认赋值就是局部变量):生效范围为当前shell进程;对当前shell之外的其它shell进程,包括当前shell的子shell进程均无效
  2. 环境变量:生效范围为当前shell进程及其子进程,子子进程..
  3. 本地变量:生效范围为当前shell进程中某代码片断,通常指函数
  4. 位置变量:$1, $2, ...来表示,用于让脚本在脚本代码中调用通过命令行传递给它的参数
  5. 特殊变量:$?, $0, $*, $@, $#,$$
  • $$:当前的shell进程编号PID :可用echo $$显示,或者echo $BASHPID; 上一级bashPID可以用 echo $PPID
    • $: Expands to the process ID of the shell. In a () subshell, it expands to the process ID of the current shell, not the subshell.

4.1. 局部变量—{set}

  • 变量赋值:name="value"
  • 可以使用引用value
    (1) 可以是直接字串:name="root"
    (2) 变量引用:name="\$USER"
    (3) 命令引用:
    name=`COMMAND` ,name=$(COMMAND)

4.1.1. 注意点1—{pstree}:

  1. 之前也总结过,变量的引用用$或者${} ,而命令的引用用 “或者$(),注意括号的区别. 一个是变量,一个是命令.
  2. 变量引用:${name} 或者 $name
    • " " 弱引用,其中的变量引用会被替换为变量值
    • ‘ ‘ 强引用,其中的变量引用不会被替换为变量值,而保持原字符串
  3. 显示已定义的所有变量:set 注意set显示的不仅仅是变量,还有函数等
  4. 删除变量:unset name

– pstree :进程树状结构 -p 可以显示PID

18:26[root@centos7 /data]# which init /usr/sbin/init 18:26[root@centos7 /data]# ll /usr/sbin/init lrwxrwxrwx. 1 root root 22 Mar 5 21:16 /usr/sbin/init -> ../lib/systemd/systemd

4.2. 环境变量—{export,declare -x,set,env,printenv}

  • 环境变量声明、赋值:
声明加赋值: export name=VALUE declare -x name=VALUE 只声明: export name declare -x name
  • 变量引用:
$name, ${name}
  • 显示所有环境变量:
env printenv export declare -x
  • 删除变量:
unset name
  • ()自动开启子进程

4.2.1. 注意点2(重要):

  1. 变量赋值的时候 变量=所附的值 ,它们之间不能有任何的空格,如果想要所附的值与=之前有空格,需使用” "" “ 等括起来才可(原因是会把空格当做分隔符,变量= 会看做命令从而找不到出现错误).最好方式就是都加上双引号,不要省略默认的双引号,避免空格(被看做分隔符)引起的错误。

  2. 变量赋值如果后面的字符串不加上双引号,则以空格为分隔符)因此,如果是一个整参数但其中有空格,必须加上双引号包住

  3. 很多命令后面的参数也是这样,空格会把他们分成多个参数,比如 mkdir " /data/backup/`date "+%F %T"`" ,date后面的两个参数得加上双引号包住,同时又因为date后面两个参数之间有空格,如果mkdir后面整体不加上双引号,则会看作是两个文件夹并给它创建上了,一个在backup文件夹内,另一个在当前文件夹内.

  4. 可以用echo $变量$变量 同时显示两个变量 ,但不可echo $变量变量 ,这样会把变量变量看做一个变量, 同上面前两条相同的逻辑,都是以空格为分隔符.

  5. $名字 ,如果不以数字开头的名字的这个变量并不存在,则echo $名字 则会输出空行

  6. $#.*,如果以数字开头,则会把$#这个看作是一个变量(参考$#当做引用参的特殊变量),echo $#.* 输出它的值(若为空值就是输出空),然后输出后面的.*里的字符内容。注意原本的变量规定不能以数字开头

  7. $###,如果要原封不动地输出(其中###是数字),则 echo $### ,要么用''单引号包含,要么用转义字符\ ,例如echo \$100

  8. 如果要输出转义字符,则需要写成\\,若要输出两个\,则要 echo \\\\ ,

  9. NUM=1 ,可以输出 echo No$NUM ,不可输出 echo $NUMNo ,必须 echo ${NUM}No 或者echo "$NUM"No .注意:花括号是包含在变量外面的 ,双引号是包含在变量外加$字符整体外面的

  10. M=10 ,N=$M ,则 echo $N 结果为10 ,但是如果这时候修改M的赋值, 比如M=20 ,则echo $N 结果仍然为10 .

  11. 主要是因为当创建N的时候虽然引用的是M的值,但是N变量会开创一个新的数据空间,存入一个10的数据,N和M指向的并不是同一个数据空间,只是内部的数值相同而已. 此时更改M的值,只是把M的数据空间内的值改掉,N指向的数据控件的值仍然是10,已经和M无关了.(疑问:到底是M的指向在赋值的时候重新更改了,N创建的时候和M指向的是同一个现在仍然没有变化;还是说N创建的时候指向的就是新开辟的数据空间,只是引用了M的数据把10这个数值存入进去而已?)

  12. 变量赋值的时候不仅可以引用别的变量的内容(第9个注意点,它只是省略了双引号),也可以引用命令的输出结果,不过注意要用反向双引号;

    • 当用echo显示变量内容时如果想要保留命令输出结果中的各种换行符,以及变量赋值的时候输入的各种空格符等等(也就是一个变量开头就有空格符,同时它存储多行内容,比如如果有变量赋值的内容是一个命令并且有换行符的时候),此时需要在$变量外加双引号,注意双引号是加在echo命令后面的$变量整体外面的。原因经过例子也可看出例如:

      18:02[root@centos7 /data]# Userinfo=" --1 `who` " 18:03[root@centos7 /data]# echo $Userinfo --1 root pts/0 2019-03-16 08:56 (gateway) root pts/1 2019-03-16 17:58 (gateway) 18:03[root@centos7 /data]# echo "$Userinfo" --1 root pts/0 2019-03-16 08:56 (gateway) root pts/1 2019-03-16 17:58 (gateway)
  13. bash所有变量默认都是字符,例子:

    18:03[root@centos7 /data]# Num1=10 18:06[root@centos7 /data]# Num2=20 18:06[root@centos7 /data]# Num3=Num1+Num2 18:06[root@centos7 /data]# echo $Num3 Num1+Num2 18:06[root@centos7 /data]# Num3=$Num1+$Num2 18:07[root@centos7 /data]# echo $Num3 10+20
  14. 变量用完最好删除,注意删除的时候直接就unset 变量名 ,不需要加$

  15. 定义的普通局部变量只能在1当前终端.2当前shell.3不能关机 中使用,不能在1.其它终端(或者窗口),2.子shell或者3.父shell,或者4.重启后(会消失)使用。

  16. bash是一个后台持续运行的程序,可以在bash中再开bash子进程,用exit退出

  17. 定义的环境变量也是只能在当前shell和子shell中使用,不能在父进程或者重启(也就是退出shell再重新进入一个shell)后使用

  18. 想要自己定义的环境变量开机存在,可以在/etc/profile.d/evn.sh 中写入export name=VALUE即可,不过这个值也只能开机时就是这个值,关机之前最后的值必须手动写入才可。可以自己写一个脚本让环境变量的值关机时保留存入这里。

  19. set命令不仅可以查看普通局部变量(比如PS1),还可以看环境变量,还可以看其他的函数,等等。注意PATH是环境变量,PS1不是。

    • export和declare -x只能看环境变量
  20. ()自动开启子进程,里面命名的变量不会影响到父进程看例子:

19:49[root@centos7 /data/lintst]# (name=zhang;echo $name) zhang 19:50[root@centos7 /data/lintst]# echo $name 19:50[root@centos7 /data/lintst]# (name=zhang;echo $name);echo $name zhang 19:51[root@centos7 /data/lintst]# name=duan;(name=zhang;echo $name);echo $name zhang duan 但是如果 19:52[root@centos7 /data/lintst]# name=duan;(echo $name);echo $name duan duan 详细一点: 19:56[root@centos7 /data/lintst]# name=duan;echo 1$name;(name=zhang;echo 2$name);echo 3$name 1duan 2zhang 3duan 19:57[root@centos7 /data/lintst]# name=duan;echo 1$name;(echo 2$name);echo 3$name 1duan 2duan 3duan 更详细一点: 19:57[root@centos7 /data/lintst]# echo $name duan 19:58[root@centos7 /data/lintst]# (echo $name) duan 19:58[root@centos7 /data/lintst]# (name=zhang; echo $name) zhang 19:59[root@centos7 /data/lintst]# echo $name duan 19:59[root@centos7 /data/lintst]# (echo $name) duan ---------------------------------------- 经过测试发现,小括号的确开启了子进程,但注意$$和$BASHPID是不同的 - 具体更多区别参考 http://codingdict.com/questions/43918 - 以及man bash 中的特殊变量 special prameters $ Expands to the process ID of the shell. In a () subshell, it expands to the process ID of the current shell, not the subshell. ----------------------------------------- 20:06[root@centos7 /data/lintst]# echo $name;echo a$$;(echo b$$;echo $name);echo $name;echo c$$;sleep 200 duan a16131 b16131 duan duan c16131 但是这样的话: echo $name;echo 1a$BASHPID;echo 2a$$;(name=wang;echo 1b$$;echo 2b$BASHPID;echo 3b$$;echo $name;);echo $name;echo 1c$$;echo 2c$BASHPID;sleep 200 duan 1a69041 2a69041 1b69041 2b70094 3b69041 wang duan 1c69041 2c69041

4.3. bash内建的环境变量

PATH SHELL USER UID HOME PWD SHLVL :shell嵌套的深度,也就是开了几个shell LANG MAIL HOSTNAME HISTSIZE _ 下划线 :上一个命令的最后一个字符串(或者是参数,以空格为分隔符来判断;如果没有参数则就是命令本身)

  • 附加:
echo ###### | passwd --stdin zhang scp -r zhang@###.###.##.### /data/scripts /data/cpdir/

4.3.1. 只读变量:只能声明,但不能修改和删除—{readonly,declare -r,-x,-i}

  • 声明只读变量:
    readonly name
    declare -r name
  • 查看只读变量:
    readonly [-p]
  • declare -r只读
  • declare -x 全局(环境)
  • declare -i 数字型
  • 注意:只读变量它删不掉也改不了,只能退出shell的时候才能去掉
    • 如果想要强行删只读变量,则方法也有,就是利用gdb工具
      1. 先安装gdb yum install gdb 2. 利用下面的方式删除只读变量即可 cat << EOF| gdb > attach $$ > call unbind_variable("只读变量名") > detach > EOF

4.3.2. 位置变量:在脚本代码中调用通过命令行传递给脚本的参数—{shift}

$1, $2, ... 对应第1、第2等参数,shift [n]换位置 $0 命令本身 $* 传递给脚本的所有参数,全部参数合为一个字符串 $@ 传递给脚本的所有参数,每个参数为独立字符串 $# 传递给脚本的参数的个数

4.3.3. 注意点3:

  1. 注意:$@ $* 只在被双引号包起来的时候才会有差异,类似前面的 变量=`who` ; echo "$变量" 需要用双引号引起来
    • 想要看出它两个的区别,需要在脚本中的次级脚本或者次级函数中(比如for循环)再次进行引用的时候才能看出来。比如初级脚本用$*$@ ,但次级脚本用 "$*" 和用 "$@"就会有区别。
    • 可以查看 https://www.cnblogs.com/Template/p/9182534.html 所写有详细解释。
  2. set -- 清空所有位置变量
  3. 注意,在history中 !n:m 第n行历史的m个参数 , *所有 ^第一个 $最后一个
  4. $0命令本身如果用 bash 脚本名的方式来执行,则不会显示脚本的路径,只显示脚本名称(我们要的就是这个效果)。但如果直接执行脚本的话会把脚本路径也给全部显示出来,所以要用basename $0.(复习:bash 脚本名不需要执行权限,直接执行脚本需要脚本有执行权限x)
    [06:15:33 root@localhost /data/dir/test]# cat test.sh #!/bin/bash echo $0; echo `basename $0`; [06:15:14 root@localhost /data/dir/test]# bash test.sh test.sh test.sh [06:15:20 root@localhost /data/dir/test]# ./test.sh ./test.sh test.sh [06:15:23 root@localhost /data/dir/test]# te teamd teamdctl teamnl tee telinit test testgdbm test.sh [06:15:23 root@localhost /data/dir/test]# test.sh /data/dir/test/test.sh test.sh
  5. $#传递参数的时候如果#数字超过10个则必须用${}给括起来不然会当做两个数字;比如$10${10}的区别。
  6. $0 如果有软链接指向脚本,则运行这个软连接的时候,$0是这个软链接的名字而不是它指向的脚本的名字,但是执行的却是脚本的代码,因此在脚本里面进行判断过后可以输出不同的功能;
    • 比如/usr/sbin/pidof 命令就是 指向的/usr/sbin/killall5,它俩并不是同一个功能的命令;
    • 通过在脚本里面判断$0的值,从而执行不同的功能。
  7. 在脚本里面用shift命令,可以让$1参数去掉,让$2变成$1,后面依次前进1位。当然也可以shift n, 可以一次移位多个。
    • 利用shift让脚本每次只处理最近的第一个参数,直到处理完所有的参数,从而实现处理不确定数目的参数的功能(当然也用for循环也行,看自己的喜好)

5. 进程使用退出状态来报告成功或失败

0 代表成功,1-255代表失败 $? 变量保存最近的命令退出状态
  • 例如:
ping -c1 -W1 hostdown &> /dev/null echo $?

5.1. bash自定义退出状态码

exit [n]:可以自定义退出状态码
  • 注意:脚本中一旦遇到exit命令,脚本会立即终止;后面的命令不再执行;终止退出状态取决于exit命令后面的数字 (没有的话默认还是0)
  • 注意:如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码
  • 利用这个自定义的返回值(可以同时配合函数中的return),可以来判断脚本执行到了什么位置退出或者什么结果退出。
  • 例子:可以用它来判断命令执行错误与否
ping -c1 -w1 ###.###.###.### &>/dev/null echo $?
最后修改日期: 2021年7月7日

作者

留言

撰写回覆或留言

发布留言必须填写的电子邮件地址不会公开。