shell 初步之变量

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhang_referee/article/details/82983745

Shell 变量分局部变量、环境变量和shell特殊变量。

在shell 中每一个变量的值都是字符串,无论你给变量赋值时有没有使用引号,值都会以字符串的形式存储,在默认情况下不会区分变量类型,即使你将整数和小数赋值给变量,它们也会被视为字符串。

 

Shell 变量的命名规范和大部分编程语言都一样:

  •        变量名由数字、字母、下划线组成;
  •        必须以字母或者下划线开头;
  •       不能使用 Shell 里的关键字(通过 help 命令可以查看保留关键字);

 

1.变量基本操作

      变量定义:

zhang@zhang-virtual-machine:~$ username='zhang'

zhang@zhang-virtual-machine:~$ hostname=localhost

   变量使用:

      使用时变量需要加$

zhang@zhang-virtual-machine:~$ echo $username
zhang
zhang@zhang-virtual-machine:~$ echo $hostname
localhost
zhang@zhang-virtual-machine:~$ echo ${username}
zhang
zhang@zhang-virtual-machine:~$ echo ${hostname}
localhost
zhang@zhang-virtual-machine:~$ 

  变量名外面的花括号是可选的,加花括号是为了帮助解释器识别变量的边界,建议一般在容易产生歧义的地方加;比如$cmd_file ,就有歧义,它可能表示$cmd这个变量连上_file ,也可能表示cmd_file这是个整体的变量,如果只想表示$cmd 然后连上_file ,可以这样写${cmd}_file。

  变量的修改

     已定义的变量,可以被重新赋值,如:

扫描二维码关注公众号,回复: 3699003 查看本文章
zhang@zhang-virtual-machine:~$ username=root
zhang@zhang-virtual-machine:~$ echo $username
root
zhang@zhang-virtual-machine:~$ 

 

  删除变量

    使用 unset 命令可以删除变量。如:

zhang@zhang-virtual-machine:~$ unset username
zhang@zhang-virtual-machine:~$ unset hostname
zhang@zhang-virtual-machine:~$ echo $username

zhang@zhang-virtual-machine:~$ echo $hostname

zhang@zhang-virtual-machine:~$ 

只读变量 

     使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。

zhang@zhang-virtual-machine:~$ name="zhang guoping"
zhang@zhang-virtual-machine:~$ echo $name
zhang guoping
zhang@zhang-virtual-machine:~$ readonly name
zhang@zhang-virtual-machine:~$ name="xiaomu xizi"
-bash: name: readonly variable
zhang@zhang-virtual-machine:~$ 

自定义变量的建议 :

1.纯数字(不带空格),定义方式可以不加引号(单或双)

2.没特殊情况,字符串一般用双引号定义,特别是多个字符串中间有空格时

3.变量内容需要原样输出 时,要用单引号('')

 

2.单引号和双引号的区别

      如果你学过php 很容易理解二者的区别:单引号包裹的值不解析,双引号包裹的值会解析

     例如:

           

zhang@zhang-virtual-machine:~$ machineBrand='Dell'
zhang@zhang-virtual-machine:~$ NickName="xiao mu xi zi"
zhang@zhang-virtual-machine:~$ echo '$machineBrand'
$machineBrand
zhang@zhang-virtual-machine:~$ echo '$NickName'
$NickName
zhang@zhang-virtual-machine:~$ echo "$machineBrand"
Dell
zhang@zhang-virtual-machine:~$ echo "$NickName"
xiao mu xi zi
zhang@zhang-virtual-machine:~$ 

 但也有特例,在awk 中:

 

zhang@zhang-virtual-machine:~$ flag=123
zhang@zhang-virtual-machine:~$ awk 'BEGIN {print "$flag"}'
$flag
zhang@zhang-virtual-machine:~$ awk 'BEGIN {print '$flag'}'
123
zhang@zhang-virtual-machine:~$ 

3.命令定义为变量

    两种方式:

       1. 使用反引号``(键盘上tab 键上一个键)

       2. 使用 () ,推荐使用小括号

 

zhang@zhang-virtual-machine:~$ showMemory=$(free -m)
zhang@zhang-virtual-machine:~$ echo $showMemory
total used free shared buffers cached Mem: 975 845 129 2 68 290 -/+ buffers/cache: 485 489 Swap: 1021 69 952
zhang@zhang-virtual-machine:~$ showHDAvailableCapacity=`df -h`
zhang@zhang-virtual-machine:~$ echo $showHDAvailableCapacity
Filesystem Size Used Avail Use% Mounted on udev 477M 4.0K 477M 1% /dev tmpfs 98M 1.5M 97M 2% /run /dev/sda1 29G 6.2G 21G 23% / none 4.0K 0 4.0K 0% /sys/fs/cgroup none 5.0M 0 5.0M 0% /run/lock none 488M 152K 488M 1% /run/shm none 100M 32K 100M 1% /run/user
zhang@zhang-virtual-machine:~$ 

4. 特殊变量

 

变量 含义
$0 当前脚本的文件名   -- 常用
$n 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是$2。
$# 传递给脚本或函数的参数个数。 --  常用
$* 传递给脚本或函数的所有参数。
$@ 传递给脚本或函数的所有参数。被双引号(" ")包含时,与 $* 稍有不同。
$? 上个命令的退出状态,或函数的返回值。--- 常用
$$ 当前Shell进程ID。对于 Shell 脚本,就是这些脚本所在的进程ID。--- 常用

 

示例:

   

  1 #! /bin/bash 
  2 
  3 echo  '$0 的值为:'$0
  4 echo '$n 以此为:' $1   ,$2,    $3,     $4
  5 echo '参数数量为:' $#
  6 echo '传递给脚本的参数有:'$*
  7 echo '传递给脚本的参数有: '$@
  8 echo '上个命令的退出状态:'$?
  9 echo '当前shell进程ID 为:'$$
~                                      

   

zhang@zhang-virtual-machine:~$ /bin/bash 2.sh "hello world" linux shell 
$0 的值为:2.sh
$n 以此为: hello world ,linux, shell,
参数数量为: 3
传递给脚本的参数有:hello world linux shell
传递给脚本的参数有: hello world linux shell
上个命令的退出状态:0
当前shell进程ID 为:4750
zhang@zhang-virtual-machine:~$ 

 

$* 和 $@ 都表示传递给函数或脚本的所有参数,不被双引号(" ")包含时,都以"$1" "$2" … "$n" 的形式输出所有参数。

但是当它们被双引号(" ")包含时,"$*" 会将所有的参数作为一个整体,以"$1 $2 … $n"的形式输出所有参数;"$@" 会将各个参数分开,以"$1" "$2" … "$n" 的形式输出所有参数。

 

 如果不熟悉set 命令的话,可以看下面的栗子:

  

zhang@zhang:~/Code/Shell$ cat distinguish.sh 
#! /bin/bash

echo 'loop in $* and without double quote'
for var in $*
do 

echo "$var"

done

echo 'loop in $@ and without double quote'
for var in $@ 
do

echo "$var"

done



echo 'loop in $* and within double quote'
for var in  "$*"
do 

echo "$var"

done

echo 'loop in $@ and without double quote'
for var in "$@"
do

echo "$var"

done


zhang@zhang:~/Code/Shell$ 

  

zhang@zhang:~/Code/Shell$ /bin/bash distinguish.sh hello world linux shell
loop in $* and without double quote
hello
world
linux
shell
loop in $@ and without double quote
hello
world
linux
shell
loop in $* and within double quote
hello world linux shell
loop in $@ and without double quote
hello
world
linux
shell
zhang@zhang:~/Code/Shell$ 

    

 

5.bash 内部变量
 
有些内部命令在目录列表是看不见的,他们由shell 本身提供,常用的内部命令有:echo ,eval ,exec ,export ,readonly,read,shift ,exit 和 点(.)


echo 变量名表
将变量名表指定的变量显示到标准输出。

eval args 
读入参数args ,并将它们组合成一个新的命令,然后执行。

zhang@zhang:~$ eval ls -a
.                 .gconf                     .vscode
..                .gnome                     .Xauthority
.atom             .gnupg                     .xinputrc
.bash_history     .ICEauthority              .xsession-errors
.bash_logout      .lantern                   .xsession-errors.old
.bashrc           .local                     公共的
.byteexec         .mozilla                   模板
.cache            .mysql_history             视频
Code              .pki                       图片
.compiz           .presage                   文档
.config           .profile                   下载
Data              .sogouinput                音乐
.dbus             .sudo_as_admin_successful  桌面
.dmrc             .thunderbird
examples.desktop  .viminfo
zhang@zhang:~$ eval echo $username
zhang
zhang@zhang:~$ 

exec 命令参数

当shell 执行到exec  语句时,不会去创建新的子进程,而是转去执行指定的命令,当指定的命令执行完时,该进程(也就是最初的shell)就终止了,所以shell程序中的exec 后面的语句讲不再被执行。

zhang@zhang:~/Code/Shell$ cat 2.sh
#! /bin/bash 

echo "begin start shell .."

exec ls -a 

echo "end shell.."
zhang@zhang:~/Code/Shell$ /bin/bash 2.sh
begin start shell ..
.  ..  1.sh  2.sh  exec_method.sh  fifo  foreach.sh  if_1.sh  if.sh  while.sh
zhang@zhang:~/Code/Shell$ 

 可以看到,exec 后面shell 语句都没有再往下执行下去!!!

  
export 变量名=value 
shell 可以用export 把它的变量向下带入子shell,从而让子进程继承父进程中的环境变量。但子shell 不能用export 把它的变量向上带入父shell .

zhang@zhang:~/Code/Shell$ export pcos="ubuntu 16.04"
zhang@zhang:~/Code/Shell$ echo $pcos
ubuntu 16.04
zhang@zhang:~/Code/Shell$ vim export.sh
zhang@zhang:~/Code/Shell$ /bin/bash export.sh
ubuntu 16.04
the shell ending...
zhang@zhang:~/Code/Shell$ cat export.sh
#/ bin/bash 

echo $pcos
echo "the shell ending..."
zhang@zhang:~/Code/Shell$ 

   export 在系统shell 中用的很频繁,下面看下栗子:

zhang@zhang:/etc/init.d$ pwd
/etc/init.d
zhang@zhang:/etc/init.d$ grep "export" ./*
./brltty:[ -n "$LANG" ] && export LANG
./console-setup:    export LANG
./cron:             [ -n "$value" ] && eval export $var=$value
./cups:    export TZ
./keyboard-setup:    export LANG
./lightdm:  export LANG LANGUAGE
./mountall.sh:	export LANG
./mysql:export PATH
./rc:export PATH
./rc:export runlevel previous
./rc:export VERBOSE
./rsync:export PATH="${PATH:+$PATH:}/usr/sbin:/sbin"
./whoopsie:DAEMON=/bin/sh -c 'export CRASH_DB_URL=https://daisy.ubuntu.com; exec whoopsie -f'
zhang@zhang:/etc/init.d$ 

  用 vim 打开console-setup 这个文件:

  

  这个LANG 是在全局变量,在这里引用到了。

 有关grep 和 vim  的用法,可以参考我之前的文章。

realdonly 变量名

用readonly 声明该变量为只读的     

还可显示所有只读变量。

zhang@zhang:/etc/init.d$ curDate
curDate:未找到命令
zhang@zhang:/etc/init.d$ curDate=$(date)
zhang@zhang:/etc/init.d$ echo curDate
curDate
zhang@zhang:/etc/init.d$ echo $curDate
2018年 10月 10日 星期三 00:36:46 CST
zhang@zhang:/etc/init.d$ readonly $curDate
bash: readonly: `2018年': 不是有效的标识符
bash: readonly: `10月': 不是有效的标识符
bash: readonly: `10日': 不是有效的标识符
bash: readonly: `星期三': 不是有效的标识符
bash: readonly: `00:36:46': 不是有效的标识符
zhang@zhang:/etc/init.d$ readonly curDate
zhang@zhang:/etc/init.d$ curDate=$(date)
bash: curDate: 只读变量
zhang@zhang:/etc/init.d$ unset curDate
bash: unset: curDate: 无法取消设定: 只读 variable
zhang@zhang:/etc/init.d$ readonly
declare -r BASHOPTS="checkwinsize:cmdhist:complete_fullquote:expand_aliases:extglob:extquote:force_fignore:histappend:interactive_comments:progcomp:promptvars:sourcepath"
declare -ir BASHPID
declare -r BASH_COMPLETION_COMPAT_DIR="/etc/bash_completion.d"
declare -ar BASH_VERSINFO='([0]="4" [1]="3" [2]="48" [3]="1" [4]="release" [5]="x86_64-pc-linux-gnu")'
declare -r CST
declare -ir EUID="1000"
declare -ir PPID="3036"
declare -r SHELLOPTS="braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor"
declare -ir UID="1000"
declare -r curDate="2018年 10月 10日 星期三 00:36:46 CST"
zhang@zhang:/etc/init.d$ 

由上面的执行结果可以得出,当变量被设置为readonly 的时候,其不能被修改及删除!!!

read 变量名表

从标准输入读入字符串并传给指定变量
可以在函数中用local 变量名的方式申明局部变量

zhang@zhang:~$ read username
zhang
zhang@zhang:~$ echo $username
zhang
zhang@zhang:~$ 

shift 语句  

shift 语句按如下方式重新命名所有的位置参数位置,即$2成为$1,$3 成为$2...在程序中每使用一次shift 语句,都使所有的位置参数依次向左移动一个位置,并使位置参数$#减1,直到减为0 为止。
 

zhang@zhang:~/Code/Shell$ cat shift.sh
#! /bin/bash 

shift
echo "begin start execute shell...."
echo '$0 the value is :'$0
echo '$1 the value is :'$1
echo '$2 the value is :'$2
echo "end shell ...."
zhang@zhang:~/Code/Shell$ /bin/bash shift.sh hello world linux 
begin start execute shell....
$0 the value is :shift.sh
$1 the value is :world
$2 the value is :linux
end shell ....
zhang@zhang:~/Code/Shell$ 

关于shift ,可以参考mysql 脚本,下面试mysql 中使用shift 的示例:

 

110 [ $# -ge 1 ] && shift
111 
112 
113 other_args="$*"   # uncommon, but needed when called from an RPM upgrade action
114            # Expected: "--skip-networking --skip-grant-tables"
115            # They are not checked here, intentionally, as it is the resposibility
116            # of the "spec" file author to give correct arguments only.
117 
118 case `echo "testing\c"`,`echo -n testing` in
119     *c*,-n*) echo_n=   echo_c=     ;;
120     *c*,*)   echo_n=-n echo_c=     ;;
121     *)       echo_n=   echo_c='\c' ;;
122 esac
123 
124 parse_server_arguments() {
125   for arg do
126     case "$arg" in
127       --basedir=*)  basedir=`echo "$arg" | sed -e 's/^[^=]*=//'`
128                     bindir="$basedir/bin"
129                     if test -z "$datadir_set"; then
130                       datadir="$basedir/data"
/shift 

猜你喜欢

转载自blog.csdn.net/zhang_referee/article/details/82983745