Linux bash shell环境变量以及语法规范

bash环境加载

Login Shell读取配置文件流程


而非登录shell仅仅会读取 ~/.bashrc


bash的登录与欢迎信息

/etc/issue 文件: 记录了bash登录前的欢迎信息,相关信息可以用 man issue 查看

/etc/motd 文件: 记录了bash登录成功后的欢迎信息


bash的环境配置文件

 login shell: 在输入帐号密码登录的时候取得的bash,例如从tty1-tty6登录

non-login shell: 取得bash不需要完整的登录流程,例如在图形界面开启Terminal



语法结构规范

赋值语句 : var=value

变量解析 : ${var}

命令解析 : ${command}

双引号 " " : 变量内容,并做转义

单引号 ' ' : 变量内容,但不做转义 

反单引号 ` ` : 同 $()

End Of File  : "EOF"

复制代码
alexis@Smilodon:~$ version=v1.0
alexis@Smilodon:~$ echo $version
v1.0
alexis@Smilodon:~$ v2="$(uname) abc ${version}"
alexis@Smilodon:~$ echo $v2
Linux abc v1.0
alexis@Smilodon:~$ echo "$LANG"
en_US.UTF-8
alexis@Smilodon:~$ echo '$LANG'
$LANG
alexis@Smilodon:~$ echo `uname -r`
3.2.0-33-generic-pae
复制代码


Shell命令结构和规范

Shell作为外围软件生态群其中一个非常重要的组件。它是操作系统最外层的接口,负责直接面向用户交互并提供内核服务,包括命令行接口(CLI)或图形界面接口(GUI)两种形式。以CLI为例,它提供一套命令规范,是一种解释性语言,将用户输入经过解释器(interpreter)输出使其转化成真正的系统调用,实现人机交互的功能。

命令结构和规范
Thompson Shell命令语言结构和规范的基础,其解释器具有跨平台的可移植性,并影响到了后来包括Bourne Shell在内的各种脚本语言设计实现。Bourne Shell的5个特性和命令规范,可以通过sh(1)手册查看原始资料。

过滤器/管道线(filter/pipeline)。这绝对是要载入Unix史册的发明,创立者是Douglas McIlroy,Thompson Shell引入并实现了这个伟大的概念——一个或多个命令组成一根过滤器的链条,由’|'或’^'符号分隔。除最后一个命令之外,每个命令的标准输出都被作为下一个命令的标准输入。这样每个命令都作为一个独立的进程来运行,并通过管道与邻近的进程相连接。圆括弧内的命令序列整体上可以替代单个命令作为过滤器实现,比如用户可以输入”(A;B)|C”。

命令序列和后台进程。分号’;'指示多个命令序列化执行。’&’符号指示该命令在后台异步执行,使得前面的管道线不必等待其终止,仅仅报告一个进程id,这样用户以后可以通过kill命令与它通信。有益于进程管理。


I/O重定向。它利用了Unix设计上的一个重要特性——一切皆文件,用三个符号表示:”重定向输出,如果文件不存在则创建它,如果文件存在则截断它;’>>’追加模式重定向输出,如果文件不存在则创建它,如果文件存在则追加输出至末尾处。


通配符扩展(globbing)。通配符的概念源自于正则表达式,使得解释器智能地处理用户不完全输入,比如记不清文件名、一次性输入多个文件等。’?'匹配任意单一字符;’*'匹配任意字符串(包括空串);成对’['和']‘定义了字符集合一个类,可匹配方括号内任意成员,用’-'两端可指定一系列连续字符匹配范围。


参数传递。这里主要引入了位置参数和选项参数的概念:’$n’指示shell调用的第n个参数替代;还定义了两个选项参数’-t’和’-c’,前者用于交互,导致shell从标准输入中读入一行作为用户执行的系统命令,后者指示shell将附带的下一个参数作为命令执行(可正确处理换行符),是对’-t’的补充,特别是调用者已经读取了命令其中某些字符的情况下。如果不带选项参数则直接读取文件名。


注:

通配符(wildcard)

*:  代表任意个任意字符

?: 代表1个任意字符

[abc]: 代表a或b或c中的一个

[a-z]: 代表 a~z这个范围

[^abc] : 代表除了a或b或c以外的字符


数据流重定向:

0: STDIN 标准输入

1: STDOUT 标准输出

2: STDERR 标准错误输出

>, >>: 输出流重定向, > 为 覆盖,>> 为追加 

cat infile 1> outfile 2>&1

将 2 重定向到 1, 再将 1 重定向到 outfile 文件,意思是将标准错误输出和标准输出都存入outfile

find /home 2> /dev/null

将错误输出 /dev/null, /dev/null是垃圾黑洞,可以将信息忽略

< : 输入重定向

cat > catfile < ~/test

用 test 文件的内容代替STDIN输入到 catfile里

<<: eof符号

cat > catfile << 'eof'

你可以使用STDIN(键盘输入)来输入到catfile,当输入eof时,输入结束,相当于点了 ctrl + d


命令执行依据 ; && ||

; : 顺序执行

&& : 且 逻辑, cmdA && cmdB, 只有cmdA成功了才会继续执行cmdB,成功的依据就是 $? 这个状态回传码

|| : 或逻辑, cmdA || cmdB 只有cmdA执行失败才会继续执行cmdB

 

管道(pipe | )

管道可以将前一个命令的stdout当作后一个命令的stdin,只有特定的管道命令才能使用

管道命令有 cut,grep,sort,wc,uniq,tee,tr,col,join,paste,expand等

而ls cd这些命令则不是管道命令,如果需要使用管道则需要用xargs作参数代换


- 号的用途

- 号可以代替 STDOUT STDIN

tar -czv -f - /home | tar -xzv -f -

第一个 - 代替stdout,第二个 - 代替stdin,想当于用tar来实现cp


算数运算

$((a*b)) : 计算a与b的乘积,只支持整数 


变量操作

export与子进程:

如果需要在子进程(在一个shell中打开另一个shell)中使用父进程的变量,则需要使用export将自定义变量转为环境变量

复制代码
alexis@Smilodon:~$ name=alexis
alexis@Smilodon:~$ echo $name
alexis
alexis@Smilodon:~$ bash
alexis@Smilodon:~$ echo $name

alexis@Smilodon:~$ exit
alexis@Smilodon:~$ export name
alexis@Smilodon:~$ bash
ealexis@Smilodon:~$ echo $name
alexis
alexis@Smilodon:~$ exit
复制代码

unset: 取消变量

alexis@Smilodon:~$ name=liu
alexis@Smilodon:~$ echo $name
liu
alexis@Smilodon:~$ unset name
alexis@Smilodon:~$ echo $name


read, array, declare

read: 读取用户输入到某个变量

alexis@Smilodon:~$ read -p "Please enter your name: " name
Please enter your name: Alexis
alexis@Smilodon:~$ echo $name
Alexis

屏幕会输出 Please enter your name: 并等待用户输入,最后将输入赋值到name


array: bash数组的赋值与输出

复制代码
alexis@Smilodon:~$ arr[0]=1
alexis@Smilodon:~$ arr[1]=2
alexis@Smilodon:~$ arr[2]=3
alexis@Smilodon:~$ echo ${arr}
1
alexis@Smilodon:~$ echo ${arr[1]}
2
alexis@Smilodon:~$ echo ${arr[2]}
3
复制代码


declare: 声明变量类型

declare -x name: 将 name 变成环境变量

declare +x name: 将 name 恢复成自定义变量

declare -i product=10*10: 将product定义成整形,这样后面的表达式就会得到计算

alexis@Smilodon:~$ declare -i product=10*10
alexis@Smilodon:~$ echo $product
100

declare -r name: 将 name 定义成只读变量

declare -a product: 将 product 定义成数组类型

declare -p product: 查看 product 的类型信息


变量微调

变量内容的删除

复制代码
alexis@Smilodon:~$ path=${PATH}
alexis@Smilodon:~$ echo ${path}
/usr/local/glassfish3/jdk7/bin:/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
alexis@Smilodon:~$ echo ${path#/*bin:}
/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
alexis@Smilodon:~$ echo ${path}
/usr/local/glassfish3/jdk7/bin:/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
alexis@Smilodon:~$ echo ${path##/*bin:}
/usr/games
复制代码


${path#/*bin:}

path: 需要微调的变量名

#: 从左边开始删除所匹配的最短的字符串,类似与正则里的非贪婪匹配

##: 表示从左边开始删除匹配的最长的字符串,类似与正则的贪婪匹配

/*bin: : 表示以 / 开头, *是通配符表示任意个任意字符, 以 bin: 结尾的字符串

注意执行这个表达式以后原来的path并不会被修改,我们只是将修改后的值输出了而已

如果要从右边开始匹配则用 % , %% 替换 #, ##


 变量内容的替换

var=${str-val}: 当变量str未设置,则 var=val, 若变量str已经设置,则var=str

var=${str:-val}: 当变量str未设置或者为空串, 则var=val

var=${str+val}: 当变量str已经设置, 则var=val,否则var=空串

var=${str:+val}: 当变量str已经设置且非空串,则var=val,否则var=空串

var=${str=val}: 若str已经设置,则var=val,str不变,若str未设置,则var=str=val

var=${str:=val}: 若str已经设置且非空,则var=val,str不变,若str未设置或为空串,则var=str=val

var=${str?val}: 若str未设置,则输出str到stderr,若str已经设置,则var=str

var=${str:?val}: 若str为设置或者为空串,则输出str到stderr,若str已经设置切非空,则var=str



source命令*--shell脚本编写

source命令用于运行shell脚本,它与bash/sh或者直接以路径运行脚本的区别在于,source是在父进程中运行,而bash是在子进程中运行,在子进程中产生的变量在父进程中将不可见,所以在运行系统配置脚本的时候应该使用source

文件比较运算符
  运算符                            描述                                            示例
  -e filename        如果 filename 存在,则为真             [ -e /var/log/syslog ]
  -d filename        如果 filename 为目录,则为真         [ -d /tmp/mydir ]
  -f filename         如果 filename 为常规文件,则为真 [ -f /usr/bin/grep ]
  -L filename        如果 filename 为符号链接,则为真  [ -L /usr/bin/grep ]
  -r filename         如果 filename 可读,则为真              [ -r /var/log/syslog ]
  -w filename       如果 filename 可写,则为真              [ -w /var/mytmp.txt ]

  $? 上一个指令的返回值


比较运算符

  -x filename         如果 filename 可执行,则为真           [ -L /usr/bin/grep ]



$# 与 $@

$0 : 脚本名称

$1 , $2 , $3 ... : 参数 1 2 3 ...

$# : 脚本参数个数

$@ : 脚本所有参数名

if ... elif ... then ... fi 条件判断语句

复制代码
#!/bin/bash
# 使用 if then else fi 获取端口状态

testing=$(netstat -tualn | grep ":80")
if [ "$testing" != "" ]; then
    echo "WWW port 80 is running in your system"
fi

testing=$(netstat -tualn | grep ":21")
if [ "$testing" != "" ]; then
    echo "FTP port 21 is running in your system"
fi

testing=$(netstat -tualn | grep ":22")
if [ "$testing" != "" ]; then
    echo "SSH port 22 is running in your system"
fi

testing=$(netstat -tualn | grep ":25")
if [ "$testing" != "" ]; then
    echo "MAIL port 25 is running in your system"
fi 
复制代码

case ... esac 选择语句

复制代码
#!/bin/bash
#test case ... esac

echo "Exit system?"
echo "1.yes 2.no"
read -p "Enter your choice: " choice
case $choice in
    "1")
        echo "Exit now"
        ;;
    "2")
        echo "Not exit"
        ;;
    *)
        echo "Plase enter 1 or 2"
        ;;
esac
复制代码

function函数

复制代码
#!/bin/bash
#use function()

function printit() {
    echo "$0 Printing $1"
}

printit "myparam"
复制代码

while 循环

复制代码
#!/bin/bash
# test while loop

while [ "$yn" != "yes" -a "$yn" != "no" ]
do
    read -p "Please input yes/no: " yn
done
echo "Good!"

i=0
s=0
while [ "$i" -lt 100 ]
do
    i=$(($i+1))
    s=$(($s+$i))
done
echo "The sum is $s"
复制代码

for的用法

1.使用 for ... in ... do ... done 

复制代码
#!/bin/bash
# test for ... in ... do ... done

# 查看子网是否联通
ip="192.168.1"

for sitenu in $(seq 1 100)
do
    ping -c 1 -w 1 "${ip}.${sitenu}" &> /dev/null && result=1 || result=0
    if [ "$result" == 1 ]; then
        echo "${ip}.${sitenu} is ON"
    else
        echo "${ip}.${sitenu} is DOWN"
    fi
done
复制代码
复制代码
#!/bin/bash

#查看目录下所有文件权限

read -p "Enter a directory: " dir

if [ "$dir" == "" -o ! -d "$dir" ]; then
    echo "The $dir is NOT exist in your system."
    exit 1
fi

filelist=$(ls $dir)
for filename in $filelist
do
    perm=""
    test -r "$dir/$filename" & perm="$perm readable"
    test -w "$dir/$filename" & perm="$perm writable"
    test -x "$dir/$filename" & perm="$perm executable"
    echo "The file $filename's permission is $perm"
done
复制代码

2. 使用 for (()) 语法

复制代码
#!/bin/bash
# test for

if [ $# != 1 ]; then
    echo "Usage $0 {maxnum}"
    exit 1;
fi

s=0
for (( i=1; i<=$1; i++ ))
do
    s=$(($s+$i))
done

echo "The sum of 1+2+3..+$1 is $s"
复制代码
复制代码
 1 #!/bin/bash  #表明该脚本使用sh或bash
 2 #This is a sample
 3 
 4 #usage of variable
 5 year=1999;  #变量赋值语句
 6 
 7 #usage of expression
 8 year=`expr $year + 1`;  #变量运算,使用expr或let
 9 echo $year
10 year="olympic'"$year  #字符串直接连接,不需要连接符
11 echo $year
12 
13 #usage of if statement  
14 if [ $year = 1999 ]
15 then
16 echo "greate"
17 else
18 echo "not greate"
19 fi  #语句使用相反的单词结束
20 
21 #usage of function and local variable
22 function echoyear {
23     local year=1998;  #局部变量使用local修饰
24     echo $year
25 }
26 echo $year;
27 echoyear;  #函数调用
28 
29 #usage of for loop
30 for day in Sun Mon Tue Ooo  #for语句,day为循环变量,in后面的是循环内容
31 do
32 echo $day
33 done
34 
35 # usage of while loop and array
36 users=(Jim Liu Dick Jack Rose)  #数组赋值
37 i=0
38 while [ ! -z ${users[$i]} ]  #数组取值使用${users[$i]}
39 do
40 echo ${users[$i]}
41 i=`expr $i + 1`
42 done
43 
44 # usage of util
45 var="I'm not empty"
46 until [ -z "$var" ];do #字符串变量需要用双引号括起,否则会抛出"too many argumet"异常,因为脚本会认为每个空格隔开的字符串都是一个参数47
48 echo $var
49 var=
50 done
51 
52 # usage of case and input from keyboard
53 echo "Hit a key, then press return" 
54 read Keypress  #从键盘读入输入
55 
56 case "$Keypress" in  #使用case语句
57 [a-z]) echo "Lowercase letter";;  #选择符可以使用正则匹配
58 [A-Z]) echo "Uppercase letter";;
59 [0-9]) echo "Digit";;
60 *) echo "Other";;
61 esac
62 
63 # usage of function
64 function pow() {  #函数参数使用$1, $2表示第一个参数和第二个参数,以此类推
65     local res=`expr $1 \* $1` # use \* instead of * here
66     return $res
67 }
68 param=5
69 pow $param  #函数传参
70 result=$?  #$?代表函数返回值,$#代表参数个数,$@代表所有参数集合
71 echo $result
72 
73 # usage of random digit
74 a=$RANDOM  #随机数的使用
75 echo $a
76 
77 # usage of select
78 OPTIONS="Hello Quit"
79 select opt in $OPTIONS  $使用select自动产生选项供用户选择
80 do
81     case $opt in
82         "Hello") 
83             echo "Hello There"
84             ;;
85         "Quit") 
86             echo "Done"
87             ;; 
88         *) 
89             echo "Bad Option"
               ;;
90     esac
91 done
92 
93 # usage of read
94 echo "Insert your name";
95 read name  #键盘输入数据
96 echo "Hi "$name
复制代码


环境变量

环境变量就是系统或软件设置的一些参数,用户环境变量就是用户登录系统后,都有自已专用的运行环境。在Windows系统中用户环境变量保存在用户家目录,Linux也是同样的。Linux常用的环境变量和环境变量的设置。

PATH环境变量作用是决定了shell将到哪些目录中寻找命令或程序。arm-linu-gcc属于命令。

export PATH=$PATH:/usr/local/arm/3.4.1/bin意思是让PATH以前的值($PATH)和新设的环境变量值(/usr/local/arm/3.4.1/bin)并列,通过符号进行分离。因为arm-Linux-gcc只有在/usr/local/arm/3.4.1/bin下才存在,所以在执行时就能通过符号分离出arm-linux-gcc的路径为/usr/local/arm/3.4.1/bin

在用户目录下用ls -a,能看见很多“.”开头的隐藏文件。如果不是用户建立的,那么这些文件都是环境设置文件。有其它Shell的设置文件,也有软件设置的文件。比如:.lftp,它就是lftp软件的设置文件。如果安装了x-window的话,菜单和桌面设置都在.local里面。


开启启动Xwindow,有些Linux发行版不会加载SHELL环境变量,因为Xwindow有自已的会话设置。例如gnome,有~/.gnomerc 或 /etc/X11/Xsession.d/55gnome-session_gnomerc。


以下内容说明特殊符号的用法

export A=/q/jing:aaa/cc/ld

export B=.:/liheng/wang

export A=/cd/cdr:$A

大家注意红色的符号:

: 表示并列含义,例如A变量值有多个,用:符号进行分离。

.表示你操作的当前目录。例如pap命令会查找B环境变量。

在/home键入pap命令,系统首先在/home目录下(即当前路径)查找关于 B 的内容,如果没有在/liheng/wang目录下查找关于B的内容。

$ 表示该变量本次定义之前的值,例如$A代表/q/jing:aaa/cc/ld。也就是说A=/cd/cdr:/q/jing:aaa/cc/ld



环境变量相关操作--只应用于当前,要永久保存需要写入到相关文件

#echo $PATH

显示PATH设置。

#env

显示当前用户变量。

#set

显示当前Shell变量。

#export

显示当前导出成用户变量的shell变量。

#a=abc

定义一个Shell变量。

#export a=abc

定义一个Shell变量,并导出成用户变量。

#unset a

清除环境变量

#readonly a

设置只读环境变量


常见的环境变量

PATH      决定了shell将到哪些目录中寻找命令或程序

HOME       当前用户主目录

HISTSIZE     历史记录数

LOGNAME     当前用户的登录名 

HOSTNAME   指主机的名称

SHELL      前用户Shell类型 

LANGUGE     语言相关的环境变量,多语言可以修改此环境变量

MAIL      当前用户的邮件存放目录 

PS1       基本提示符,对于root用户是#,对于普通用户是$

PS2       附属提示符,默认是“>”


几个重要的环境变量

$OSTYPE: 操作系统类型

$HOSTTYPE:  主机默认安装的软件主要类型,32位的有 i386, i586, i686, 64位为 x86_64

$MACHTYPE:  安装的机器类型

$$: 当前shell的PID

$?: 上一个命令的返回值,如果上一个命令执行成功则返回0

$0 这个程序的执行名字

$n  这个程序的第n个参数值,n=1...9

$*  这个程序的所有参数
$# 这个程序的参数个数
$! 执行上一个背景指令的PID

Linux环境变量设置文件

/etc/profile

全局用户,应用于所有的Shell。

/$HOME/.profile

当前用户,应用于所有的Shell。

/etc/bash_bashrc

全局用户,应用于Bash Shell。

~/.bashrc

局部当前,应用于Bash Sell。


你可能感兴趣的:(Linux)