Shell脚本攻略02-玩转变量与环境变量

简介: Shell脚本攻略02-玩转变量与环境变量

概述


变量是任何一种编程语言都必不可少的组成部分,用于存放各类数据。


脚本语言通常不需要在使用变量之前声明其类型。只需要直接赋值就可以了。


在Bash中,每一个变量的值都是字符串。


无论你给变量赋值时有没有使用引号,值都会以字符串的形式存储。


有一些特殊的变量会被shell环境和操作系统环境用来存储一些特别的值,这类变量就被称为环境变量。


理论知识


变量采用常见的命名方式进行命名。当应用程序执行时,它接收一组环境变量。

可以使用env命令查看所有与终端相关的环境变量。


[root@entel1 ~]# env
HOSTNAME=entel1
TERM=xterm
SHELL=/bin/bash
HISTSIZE=1000
.......省略


对于进程来说,其运行时的环境变量可以使用下面的命令来查看:

cat /proc/$PID/environ


其中,将PID设置成相关进程的进程ID(PID总是一个整数)。

如何获取$PID呢?

假设有一个叫做gedit的应用程序正在运行。我们可以使用pgrep命令获得gedit的进程ID:

$ pgrep gedit
12501


那么,你就可以通过以下命令获得与该进程相关的环境变量:

$ cat /proc/12501/environ
GDM_KEYBOARD_LAYOUT=usGNOME_KEYRING_PID=1560USER=slynuxHOME=/home/slynux
.........


环境变量远不止这些,只是由于对页面篇幅的限制,在这里删除了其他很多环境变量。


pgrep 用法

[root@entel2 ~]# pgrep --help
pgrep: invalid option -- '-'
Usage: pgrep [-flvx] [-d DELIM] [-n|-o] [-P PPIDLIST] [-g PGRPLIST] [-s SIDLIST]
    [-u EUIDLIST] [-U UIDLIST] [-G GIDLIST] [-t TERMLIST] [PATTERN]


pgrep程序检查在系统的中活动进程,报告进程属性匹配命令行上指定条件的进程的ID。

pgrep 查找的是程序名,而不包其参数

pgrep相当于 ps -eo pid,cmd |awk '{print $1,$2}'|grep keyword


20161203235339543.png

20161203235404435.png

  1. pgrep 通常和pkill在一起用,在指定条件下kill进程

如果pgrep不是很熟悉,可以用ps -ef

[root@entel2 ~]# ps -ef|less
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 Oct25 ?        00:00:15 /sbin/init
root         2     0  0 Oct25 ?        00:00:00 [kthreadd]


取 第二列 PID


举例:

[root@entel2 ~]# pgrep java
4309
[root@entel2 ~]# cat /proc/4309/environ 
APP_XMX_SIZE_zmcDaemon=128MHOSTNAME=tbpr_app1SHELL=/bin/bashTERM=vt100HISTSIZE=1000SSH_CLIENT=172.25.246.66 42562 22OLDPWD=/home/settWeb/zmc_agent/daemonSSH_TTY=/dev/pts/9USER=settWebJRE_HOME=/usr/lib/jvm/jdk1.7.0_80/jreLS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.......省略

上面的命令返回一个包含环境变量以及对应变量值的列表。每一个变量以name=value的形式来描述,彼此之间由null字符(\0)分隔。


看起来是不是很懵逼,一团乱糟糟的很难以查看。


如果你将\0替换成\n,那么就可以将输出重新格式化,使得每一行显示一组“变量=值”。替换可以使用tr命令来实现:

[root@entel2 ~]# cat /proc/4309/environ |tr '\0' '\n'
APP_XMX_SIZE_zmcDaemon=128M
HOSTNAME=tbpr_app1
SHELL=/bin/bash
TERM=vt100
HISTSIZE=1000
SSH_CLIENT=172.25.246.66 42562 22
OLDPWD=/home/settWeb/zmc_agent/daemon
SSH_TTY=/dev/pts/9
USER=settWeb
JRE_HOME=/usr/lib/jvm/jdk1.7.0_80/jre
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;....省略

对变量和环境变量进行赋值


变量赋值

变量可以通过以下方式进行赋值:

var=value


var是变量名, value是赋给变量的值。

如果value不包含任何空白字符(例如空格),那么它就不需要使用引号进行引用,否则必须使用单引号或双引号。


注意, var = value不同于var=value。把var=value写成var = value是一个常见的错误,但前者是赋值操作,后者则是相等操作。

在变量名之前加上$前缀就可以打印出变量的内容:

var="value" #给变量var赋值
echo $var

或者

echo ${var}


输出value

栗子:

[root@entel1 ~]# cat -b var.sh 
     1  #!/bin/bash
     2  var="xiaogongjiang bash"
     3  var2=xiaogongjaing
     4  var3 = wrong_use
     5  echo $var
     6  echo ${var2}
     7  echo $var3
[root@entel1 ~]# ./var.sh 
./var.sh: line 4: var3: command not found
xiaogongjiang bash
xiaogongjaing
[root@entel1 ~]# 


可以在printf或echo命令的双引号中引用变量值。

[root@entel1 Templates]# cat variables.sh 
#!/bin/bash
lesson=shell
count=100
echo "we have ${count}  $lesson  ,output by echo"
#换行 \n
printf "we have $count $lesson output by printf \n" 
[root@entel1 Templates]# ./variables.sh 
we have 100  shell  ,output by echo
we have 100 shell output by printf 
[root@entel1 Templates]# 


注意:

使用单引号时,变量不会被扩展(expand),将依照原样显示。这意味着:

$ echo '$var' will print $var


但如果变量var已经定义过,那么$ echo "$var"会打印出该变量的值;

如果没有定义过,则什么都不打印。

[root@entel1 Templates]# cat test.sh 
#!/bin/bash
var=xiaogongjiang
echo '$var' will print $var
echo '$var2' will print $var2
[root@entel1 Templates]# ./test.sh --观察var2的输出为空,因为未定义
$var will print xiaogongjiang
$var2 will print
[root@entel1 Templates]# 


环境变量赋值


环境变量是未在当前进程中定义,而从父进程中继承而来的变量。

例如环境变量,HTTP_PROXY,它定义了互联网连接应该使用哪个代理服务器。

该环境变量通常被设置成:

HTTP_PROXY=192.168.1.23:3128
export HTTP_PROXY


export命令用来设置环境变量。至此之后,从当前shell脚本执行的任何应用程序都会继承这个变量。

我们可以按照自己的需要,在执行的应用程序或者shell脚本中导出特定的变量。


在默认情况下,有很多标准环境变量可供shell使用。

PATH就是其中之一。

[root@entel1 Templates]# echo $PATH
/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin


在给出所要执行的命令后, shell会自动在PATH环境变量所包含的目录列表中(各目录路径之间以冒号分隔)查找对应的可执行文件。

PATH通常定义在/etc/environment或/etc/profile或~/.bashrc中。


PATH中添加一条新路径


如果需要在PATH中添加一条新路径,可以使用:

$ export PATH="$PATH:/home/user/bin"


也可以使用

$ PATH="$PATH:/home/user/bin"
$ export PATH


这样,我们就将/home/user/bin添加到了PATH中。

还有一些众所周知的环境变量: HOME、 PWD、 USER、 UID、 SHELL等


Addition


下面我们再多看些有关标准变量和环境变量的技巧。


获得字符串长度${#}


[root@entel1 Templates]# cat test.sh 
#!/bin/bash
var=xiaogongjiang
echo "var's length  ${#var}"
[root@entel1 Templates]# ./test.sh 
var's length  13


识别当前所使用的shell

可以用下面的方法获知当前使用的是哪种shell:

echo $SHELL


也可以用

echo $0


检查是否为超级用户


UID是一个重要的环境变量,可以用于检查当前脚本是以超级用户还是以普通用户的身份运行的。

root用户的UID是0。

例如:

[root@entel1 Templates]# cat test.sh 
#!/bin/bash
#检测用户是否是root用户
#[] 两侧记得带空格 [$UID -ne 0] 会报错
if [ $UID -ne  0 ]; then 
    echo Non root user 
else 
    echo Root user 
fi
[root@entel1 Templates]# ./test.sh 
Root user


修改Bash提示字符串( username@hostname:~$)


http://blog.csdn.net/yangshangwei/article/details/52928009


当我们打开终端或是运行shell时,会看到类似于user@hostname:/home/$的提示字符串。

不同GNU/Linux发布版中的提示及颜色略有不同。我们可以利用PS1环境变量来定制提示文本。


默认的shell提示文本是在文件~/.bashrc中的某一行设置的。


 可以使用如下命令列出设置变量PS1的那一行:

$ cat ~/.bashrc | grep PS1
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '

 如果要设置一个定制的提示字符串,可以输入:

$ PS1="PROMPT>"
PROMPT> Type commands here #提示字符串已经改变


 我们可以利用类似\e[1;31的特定转义序列来设置彩色的提示字符串

还有一些特殊的字符可以扩展成系统参数。

例如: \u可以扩展为用户名, \h可以扩展为主机名,而\w可以扩展为当前工作目录。


使用函数添加环境变量


环境变量通常用于存储路径列表,这些路径用于搜索可执行文件、库文件等。

例如$PATH、$LD_LIBRARY_PATH,它们通常看起来像这样:

PATH=/usr/bin;/bin
LD_LIBRARY_PATH=/usr/lib;/lib

这意味着只要shell需要运行二进制可执行文件时,它会首先查找/usr/bin,然后是/bin。


场景举例


当你必须使用源代码编译生成程序并将其安装到某个特定路径中时,有项极其常见的任务就是将该程序的bin目录加入PATH环境变量。


假设我们要将myapp安装到/opt/myapp,它的二进制文件在bin目录中,库文件在lib目录中。

实现方法

export PATH=/opt/myapp/bin:$PATH
export LD_LIBRARY_PATH=/opt/myapp/lib;$LD_LIBRARY_PATH


PATH和LD_LIBRARY_PATH现在看起来应该像这样:

PATH=/opt/myapp/bin:/usr/bin:/bin
LD_LIBRARY_PATH=/opt/myapp/lib:/usr/lib;/lib


不过我们可以把下面的函数加入.bashrc-,让一切变得更轻松些:

prepend() { [ -d "$2" ] && eval $1=\"$2':'\$$1\" && export $1; }


像下面这样来使用该函数:

prepend PATH /opt/myapp/bin
prepend LD_LIBRARY_PATH /opt/myapp/lib


函数分析


我们定义了名为prepend()的函数,它首先检查该函数第二个参数所指定的目录是否存在。

如果存在, eval表达式将第一个参数所指定的变量值设置成第二个参数的值加上“ :”(路径分隔符),随后再跟上首个参数的原始值。


完善函数


不过,有一点需要留意。在进行添加时,如果变量为空,则会在末尾留下一个“ :”。


要解决这个问题,可以将该函数再进行一些修改

prepend() { [ -d "$2" ] && eval $1=\"$2\$\{$1:+':'\$$1\}\" && export $1 ; }


在这个函数中,我们引入了一种shell参数扩展的形式:

${parameter:+expression}


如果parameter有值且不为空,则使用expression的值。

通过这次修改,在追加环境变量时,当且仅当旧值存在,才会增加。

相关文章
|
5天前
|
Shell Linux
【linux】Shell脚本中basename和dirname的详细用法教程
本文详细介绍了Linux Shell脚本中 `basename`和 `dirname`命令的用法,包括去除路径信息、去除后缀、批量处理文件名和路径等。同时,通过文件备份和日志文件分离的实践应用,展示了这两个命令在实际脚本中的应用场景。希望本文能帮助您更好地理解和应用 `basename`和 `dirname`命令,提高Shell脚本编写的效率和灵活性。
60 32
|
4月前
|
Shell
一个用于添加/删除定时任务的shell脚本
一个用于添加/删除定时任务的shell脚本
150 1
|
3月前
|
Shell Linux 测试技术
6种方法打造出色的Shell脚本
6种方法打造出色的Shell脚本
104 2
6种方法打造出色的Shell脚本
|
3月前
|
XML JSON 监控
Shell脚本要点和难点以及具体应用和优缺点介绍
Shell脚本在系统管理和自动化任务中扮演着重要角色。尽管存在调试困难、可读性差等问题,但其简洁高效、易于学习和强大的功能使其在许多场景中不可或缺。通过掌握Shell脚本的基本语法、常用命令和函数,并了解其优缺点,开发者可以编写出高效的脚本来完成各种任务,提高工作效率。希望本文能为您在Shell脚本编写和应用中提供有价值的参考和指导。
127 1
|
3月前
|
Ubuntu Shell 开发工具
ubuntu/debian shell 脚本自动配置 gitea git 仓库
这是一个自动配置 Gitea Git 仓库的 Shell 脚本,支持 Ubuntu 20+ 和 Debian 12+ 系统。脚本会创建必要的目录、下载并安装 Gitea,创建 Gitea 用户和服务,确保 Gitea 在系统启动时自动运行。用户可以选择从官方或小绿叶技术博客下载安装包。
130 2
|
4月前
|
监控 网络协议 Shell
ip和ip网段攻击拦截系统-绿叶结界防火墙系统shell脚本
这是一个名为“小绿叶技术博客扫段攻击拦截系统”的Bash脚本,用于监控和拦截TCP攻击。通过抓取网络数据包监控可疑IP,并利用iptables和firewalld防火墙规则对这些IP进行拦截。同时,该系统能够查询数据库中的白名单,确保合法IP不受影响。此外,它还具备日志记录功能,以便于后续分析和审计。
84 6
|
3月前
|
运维 监控 Shell
深入理解Linux系统下的Shell脚本编程
【10月更文挑战第24天】本文将深入浅出地介绍Linux系统中Shell脚本的基础知识和实用技巧,帮助读者从零开始学习编写Shell脚本。通过本文的学习,你将能够掌握Shell脚本的基本语法、变量使用、流程控制以及函数定义等核心概念,并学会如何将这些知识应用于实际问题解决中。文章还将展示几个实用的Shell脚本例子,以加深对知识点的理解和应用。无论你是运维人员还是软件开发者,这篇文章都将为你提供强大的Linux自动化工具。
|
4月前
|
存储 Java Shell
Shell 变量
10月更文挑战第2天
41 0
|
4月前
|
存储 运维 监控
自动化运维:使用Shell脚本简化日常任务
【9月更文挑战第35天】在IT运维的日常工作中,重复性的任务往往消耗大量的时间。本文将介绍如何通过编写简单的Shell脚本来自动化这些日常任务,从而提升效率。我们将一起探索Shell脚本的基础语法,并通过实际案例展示如何应用这些知识来创建有用的自动化工具。无论你是新手还是有一定经验的运维人员,这篇文章都会为你提供新的视角和技巧,让你的工作更加轻松。
133 2
|
4月前
|
存储 Shell Linux
【Linux】shell基础,shell脚本
Shell脚本是Linux系统管理和自动化任务的重要工具,掌握其基础及进阶用法能显著提升工作效率。从简单的命令序列到复杂的逻辑控制和功能封装,Shell脚本展现了强大的灵活性和实用性。不断实践和探索,将使您更加熟练地运用Shell脚本解决各种实际问题
64 0