特点:1 shell变量没有数据类型的区分
2 Shell 把任何存储在变量中的值,皆视为以字符组成的“字符串”。
3 设定的变量值只在当前shell环境中有作用
4 不能以数字开头
5 =号两边不能存在空格
6 若变量值中存在空格,必须用括号将变量值括起来 I = “Jack Black”
在编写shell时,如果变量未赋值,后续使用时不会出现任何错误。如果要显示错误提示,则需要命令 shopt -s -o nounset
shopt -s -o nounset解析如下
.范例如下
[root@localhost ~]# vim test1.sh #!/bin/bash echo $Infomix [root@localhost ~]# sh test1.sh # 未提示任何错误 [root@localhost ~]# vim test1.sh [root@localhost ~]# vim test1.sh #!/bin/bash shopt -s -o nounset #添加错误提示 echo $Infomix [root@localhost ~]# sh test1.sh test1.sh:行4: Infomix: 为绑定变量 #提示错误
二 取得变量值
$变量名称=${变量名称}
如果变量作为字符的一部分输出时,则必须用${}将变量括起来,否则shell将无法识别变量。$会将后面的所有字符当做变量的一部分,肯定是找不到变量的
[root@localhost ~]# myname='lsq' [root@localhost ~]# echo $myname lsq [root@localhost ~]# echo ${myname} lsq [root@localhost ~]# echo hello${myname}boy hellolsqboy [root@localhost ~]# echo hello$mynameboy hello
如果后面接的不是字符,也不是_下划线,则不需要{}来括起来。变量后接中文也是可以的。呵呵。
[root@localhost ~]# dir2=sbin [root@localhost ~]# echo /usr/local/$dir2/config /usr/local/sbin/config
$是去变量值的特殊字符,如果要显示$怎么操作,转义字符 或者用单引号括起来 '$i'
Bash除了echo之外,还提供了一个c类似的printf的语法。感觉这个东西有字符串格式化的意思。体会一下
%s 以字符串的形式显示变量值
[root@localhost ~]# printf "%s" "$dir2" sbin[root@localhost ~]# printf "%s " "$dir2" sbin # 和c语言一样,都是换行的意思。 [root@localhost ~]#
[root@localhost ~]# SP='ABC 123 XYZ' [root@localhost ~]# printf "%q " "$SP" ABC 123 XYZ #%q会将变量值中的特殊字符,用字符转义,实例中就是在空格前加
三 取消与清空变量
unset 变量名
unset -v 变量名 -v 表示取消的是变量
unset -f 函数名 -f 表示取消的是函数
清空变量值
变量名= 跟unset的区别是,清空变量值,该变量还存在,只不过值变成空而已。unset则会将变量销毁
四 变量和引号
双引号和单引号的区别
前边说过,变量赋值可以用单引号或者双引号,但是二者是有区别的
双引号相对于单引号可以有如下操作
1 替换变量 例
[root@localhost shellscript]# vim test2.sh #! /bin/bash shopt -s -o nounset myname="Bash shell" #echo $myname hello="hello ,i am $myname" echo $hello [root@localhost shellscript]# sh test2.sh hello ,i am Bash shell #将变量名myname用Bash shell 进行了替换
#但是如果我们用单引号
[root@localhost shellscript]# vim test2.sh
#! /bin/bash
shopt -s -o nounset
myname="Bash shell"
#echo $myname
#hello="hello ,i am $myname"
hello='hello ,i am ,$myname'
echo $hello
[root@localhost shellscript]# sh test2.sh
hello ,i am ,$myname #看到了么?他不会替换,他会将变量名整体输出
如果要在双引号中输出变量名而非替换,则需要用到转义字符转义
2 替换命令执行结果
3 替换算数运算结果
四 变量的有效范围
变量的有效范围就是当前所处的shell环境
如果要让变量在所有的shell都执行,那就需要将该变量设置成环境变量
通过 export 命令就可以将变量设置成环境变量。
export testVar="hello world" 或 testVar="hello world" export testVar
取消环境变量
testVar=
或者
unset testVar
五 Bash 的内置变量
六 设置只读变量
readonly 命令和declare -r 命令
readonly 或 readonly -p 列出只读属性的变量列表
readonly -f 函数名 设置该函数不可修改
readonly -a 数组变量 设置后该数组为只读数组
例
s[0]=10 s[1]=20 s[2]=30 readonly -a s #设置该数组为只读数组 s[3]=50 该行 会报错
调整变量的其他属性
[root@localhost ~]# declare -i I=60 #设定该变量为整数变量 [root@localhost ~]# echo $I 60 [root@localhost ~]# I="test" #如果传入字符串,则会将该变量变为0 [root@localhost ~]# echo $I 0 [root@localhost ~]#
七 取别名
alias 变量名
[root@localhost ~]# alias -p #列出别名列表 alias cp='cp -i' alias egrep='egrep --color=auto' alias fgrep='fgrep --color=auto' alias grep='grep --color=auto' alias l.='ls -d .* --color=auto' alias ll='ls -l --color=auto' alias ls='ls --color=auto' alias mv='mv -i' alias perlll='eval `perl -Mlocal::lib`' alias rm='rm -i' alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
alias 别名=指令 注意:=号两边不允许有空格。 如需要有空格,必须用括号括起来。如上例中alias l.='ls -d .*'
unalias 取消别名
八 自定义工作环境
以一般账号的角色工作时,默认的工作环境配置文件为
这里的~目录,一般指的是家目录
自定义工作环境的意义:让用户登录主机时,能拥有安全及易于执行命令的环境。包括 建立文件的权限 命令搜寻路径 环境变量 命令提示符 别名 喜好比较器 显示文件使用的颜色等
[root@localhost ~]# cd /root [root@localhost ~]# cat .bash_profile #这个是root的默认配置文件 # .bash_profile # Get the aliases and functions if [ -f ~/.bashrc ]; then . ~/.bashrc fi # User specific environment and startup programs PATH=$PATH:$HOME/bin export PATH
[root@localhost /]# cd home #这个是普通用户的配置文件,普通用户在家目录 /home目录中 [root@localhost home]# ls ftptest lsq [root@localhost home]# cd lsq [root@localhost lsq]# cat .bash_profile # .bash_profile # Get the aliases and functions if [ -f ~/.bashrc ]; then . ~/.bashrc fi # User specific environment and startup programs PATH=$PATH:$HOME/.local/bin:$HOME/bin export PATH
管理员维护的环境配置文件一般有三个 /etc/profile /etc/bashrc /etc/skel目录下的文件
其中 /etc/profile和/etc/bashrc中的设定,会影响所有账号的使用环境。
在/etc/profile中,通常会设定 umask,PATH,多国语言环境,提示符号,别名等
这是我本机的profile
[root@localhost etc]# cat profile # /etc/profile # System wide environment and startup programs, for login setup # Functions and aliases go in /etc/bashrc # It's NOT a good idea to change this file unless you know what you # are doing. It's much better to create a custom.sh shell script in # /etc/profile.d/ to make custom changes to your environment, as this # will prevent the need for merging in future updates. pathmunge () { case ":${PATH}:" in *:"$1":*) ;; *) if [ "$2" = "after" ] ; then PATH=$PATH:$1 else PATH=$1:$PATH fi esac } if [ -x /usr/bin/id ]; then if [ -z "$EUID" ]; then # ksh workaround EUID=`/usr/bin/id -u` UID=`/usr/bin/id -ru` fi USER="`/usr/bin/id -un`" LOGNAME=$USER MAIL="/var/spool/mail/$USER" fi # Path manipulation if [ "$EUID" = "0" ]; then pathmunge /usr/sbin pathmunge /usr/local/sbin else pathmunge /usr/local/sbin after pathmunge /usr/sbin after fi HOSTNAME=`/usr/bin/hostname 2>/dev/null` HISTSIZE=1000 if [ "$HISTCONTROL" = "ignorespace" ] ; then export HISTCONTROL=ignoreboth else export HISTCONTROL=ignoredups fi export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE HISTCONTROL # By default, we want umask to get set. This sets it for login shell # Current threshold for system reserved uid/gids is 200 # You could check uidgid reservation validity in # /usr/share/doc/setup-*/uidgid file if [ $UID -gt 199 ] && [ "`/usr/bin/id -gn`" = "`/usr/bin/id -un`" ]; then umask 002 else umask 022 fi for i in /etc/profile.d/*.sh /etc/profile.d/sh.local ; do if [ -r "$i" ]; then if [ "${-#*i}" != "$-" ]; then . "$i" else . "$i" >/dev/null fi fi done unset i unset -f pathmunge
一下是本机普通用户的配置环境,在/etc/skel目录中
[root@localhost ~]# cd /etc/skel [root@localhost skel]# ls [root@localhost skel]# ls -la 总用量 28 drwxr-xr-x. 3 root root 78 4月 11 2018 . drwxr-xr-x. 162 root root 12288 10月 14 15:36 .. -rw-r--r--. 1 root root 18 10月 31 2018 .bash_logout -rw-r--r--. 1 root root 193 10月 31 2018 .bash_profile -rw-r--r--. 1 root root 231 10月 31 2018 .bashrc drwxr-xr-x. 4 root root 39 8月 19 11:00 .mozilla [root@localhost skel]# cat .bash_profile # .bash_profile # Get the aliases and functions if [ -f ~/.bashrc ]; then . ~/.bashrc fi # User specific environment and startup programs PATH=$PATH:$HOME/.local/bin:$HOME/bin export PATH [root@localhost skel]# cat .bashrc # .bashrc # Source global definitions if [ -f /etc/bashrc ]; then . /etc/bashrc fi # Uncomment the following line if you don't like systemctl's auto-paging feature: # export SYSTEMD_PAGER= # User specific aliases and functions [root@localhost skel]# cat .bash_logout # ~/.bash_logout
九 数组
bash数组的特点: 1 没有个数限制 2 可以跳跃赋值 3 所以可以表达式表示,如1+2 4 bash只支持一维数组
[root@localhost ~]# A[0]=5 [root@localhost ~]# A[1]=10 [root@localhost ~]# A[2]=28 [root@localhost ~]# A[3]="bash shell"
[root@localhost ~]# echo $A
5
[root@localhost ~]# echo $A[0] 看出跟上一句的区别了么?他走的是C语言的路子,读取$A直接取得是数组首地址的值,如果要取数组剩余标的值,就需要下面的操作.也就是将整个数组包含小标用大括号括起来,表示一个整体变量,用$读出 5[0] [root@localhost ~]# echo $(A[0]) bash: A[0]: 未找到命令... [root@localhost ~]# echo ${A[0]} #这里要注意一下,取数组值的时候,用到的是{}大括号 5 [root@localhost ~]# echo ${A[1+1]} 28 [root@localhost ~]# B={23 88 99 66} bash: 88: 未找到命令... [root@localhost ~]# B=(23 88 99 66) #数组群体赋值的时候,用到的是()小括号。这点要注意 [root@localhost ~]# echo ${B[0]} 23
正因为,shell数组没有个数的限制,也就是说,不需要在使用数组的时候,首先要固定一下数组的长度,所以,他的自由度很大,可以给某一下标无限,跳跃似的赋值
取出所有数组元素
用@符号来代替数组下标
[root@localhost ~]# echo ${A[@]} 5 10 28 bash shell
取得数组个数
${#A[@]}的格式来取得数组的小标
[root@localhost ~]# echo ${#A[@]} 4
如果数组某个下标表示的值为字符串,还可以取得该字符串的长度
${#A[索引]}
如上例中,A【3】的值是bash shell。我们要想知道他的长度可以采用如下
[root@localhost ~]# echo ${#A[3]} 10
删除数组和删除变量函数都用的同一个命令。unset
如果要删除整个数组可以用 unset A
如果要删除数组中的某个赋值 unset A[3] 就会将bash shell 删除。我们来试一下
[root@localhost ~]# unset A[3] #将第三个数组值删除 [root@localhost ~]# echo ${#A[3]} 0 #数组长度变为0 [root@localhost ~]# echo ${A[3]} #值变为空 [root@localhost ~]# echo ${A[@]} 5 10 28 #打印所有变量的时候,也可以证明A[3]确实没有了 [root@localhost ~]# unset A #取消掉整个数组A [root@localhost ~]# echo ${A[@]} #整个数组A确实取消掉了。没有数组元素了 [root@localhost ~]#
十 Here Document
bash 有一种特殊的程序区域。就是 Here Document,也可以用来设定变量。
语法为 命令 <<标记
[root@localhost ~]# wc -l << countline > line1 > line2 > line3 > countline 3
Here Document也支持变量替换。在输入的内容中,如果有变量,bash会在转向前,将变量值进行替换
[root@localhost ~]# From="From: me@example.edu.cn" #四个变量 [root@localhost ~]# To="To: you@example.edu.cn" [root@localhost ~]# Subject="Subject: Hello world" [root@localhost ~]# Msg="happy new year" [root@localhost ~]# EM="20090310.txt" [root@localhost ~]# cat > $EM <<here #进行转向 > $From > $To > $Subject > > $Msg > here [root@localhost ~]# cat 20090310.txt From: me@example.edu.cn To: you@example.edu.cn Subject: Hello world happy new year
利用Here Document做多行批注
bash中,只支持单行注释,#来开头
利用Here Document来做多行批注,可以用:来操作 : <<DO-NOTHING
第一行,第二行,第三行 DO-NOTHING
利用Here Document夹带私货
书中就有一个夹带私货的例子。他是用Here Document写了一个C程序,然后在编译执行他,以便达到不可告人的目的,看看他是咋写的
[root@localhost ShellScript]# vim create_prg.sh #! /bin/bash echo "正在产生hello.c。。。。" echo cat <<'EOF' >hello.c #include <stdio.h> int main() { printf("Hello world! "); return 0; } EOF echo "编译hello.c........" echo #编译Hello.c,并产生执行文件 gcc -o hello hello.c #若编译成功,则运行 if [ $? -eq 0 ]; then echo "执行 hello....." echo ./hello else echo '执行失败' fi "create_prg.sh" [新] 27L, 374C 已写入 [root@localhost ShellScript]# sh create_prg.sh 正在产生hello.c。。。。 编译hello.c........ 执行 hello..... Hello world! [root@localhost ShellScript]# ls 20090310.txt create_prg.sh hello hello.c
这样就可以动态编写c程序,动态执行。神不知鬼不觉。。。