Shell基础知识

Shell 简介

Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。
Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。
Ken Thompson 的 sh 是第一种 Unix Shell,Windows Explorer 是一个典型的图形界面 Shell。

Shell 脚本

Shell 脚本(shell script),是一种为 shell 编写的脚本程序。
业界所说的 shell 通常都是指 shell 脚本,但读者朋友要知道,shell 和 shell script 是两个不同的概念。
由于习惯的原因,简洁起见,本文出现的 “shell编程” 都是指 shell 脚本编程,不是指开发 shell 自身。

Shell 脚本编译器

打开文本编辑器(可以使用 vi/vim 命令来创建文件),新建一个文件 test.sh,扩展名为 sh(sh代表shell),扩展名并不影响脚本执行,见名知意就好,如果你用 php 写 shell 脚本,扩展名就用 php 好了。
输入一些代码,第一行一般是这样:

#!/bin/bash
echo "Hello World !"

#! 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell。
echo 命令用于向窗口输出文本。

运行 Shell 脚本有两种方法:

1、作为可执行程序

将上面的代码保存为 test.sh,并 cd 到相应目录:

[root@ chenc01 ~]# chmod +x ./test.sh  # 使脚本具有执行权限
[root@ chenc01 ~]# ./test.sh           # 执行脚本

# 注意,一定要写成 ./test.sh,而不是 test.sh,运行其它二进制的程序也一样,直接写 test.sh,linux 系统会去 PATH 里寻找有没有叫 test.sh 的,而只有 /bin, /sbin, /usr/bin,/usr/sbin 等在 PATH 里,你的当前目录通常不在 PATH 里,所以写成 test.sh 是会找不到命令的,要用 ./test.sh 告诉系统说,就在当前目录找。
2、作为解释器参数

这种运行方式是,直接运行解释器,其参数就是 shell 脚本的文件名,如:

[root@ chenc01 ~]# /bin/sh test.sh
[root@ chenc01 ~]# /bin/php test.php

Shell变量

1、系统变量

在命令行提示符直接执行env、set查看系统或环境变量。env显示用户环境变量,set显示Shell预先定义好的变量以及用户变量。可以通过export导出成用户变量。

一些写Shell脚本时常用的系统变量:

$Shell默认Shell
$HOME当前用户家目录
$IFS内部字段分隔符
$LANG默认语言
$PATH默认可执行程序路径
$PWD当前目录
$UID当前用户ID
$USER当前用户
$HISTSIZE历史命令大小,可通过HISTTIMEFORMAT变量设置命令执行时间
$RANDOM随机生成一个0至32767的整数
$HOSTNAME主机名
2、普通变量与临时环境变量

普通变量定义:VAR=value

临时环境变量定义:export VAR=value

变量引用:$VAR

下面看下他们之间区别:

Shell进程的环境变量作用域是Shell进程,当export导入到系统变量时,则作用域是Shell进程及其Shell子进程。

[root@ chenc01 ~]# ps axjf | grep pts
  1090   1129   1129   1129 ?            -1 Ss       0   0:00  \_ sshd: root@pts/0 
  1129   1131   1131   1131 pts/0      1131 Ss+      0   0:00  |   \_ -bash
  1090   1188   1188   1188 ?            -1 Ss       0   0:00  \_ sshd: root@pts/1 
  1188   1190   1190   1190 pts/1      1235 Ss       0   0:00      \_ -bash
  1190   1235   1235   1190 pts/1      1235 R+       0   0:00          \_ ps axjf
  1190   1236   1235   1190 pts/1      1235 S+       0   0:00          \_ grep --color=auto pts
[root@ chenc01 ~]# echo $$
1190
[root@ chenc01 ~]# VAR=123
[root@ chenc01 ~]# echo $VAR
123
[root@ chenc01 ~]# bash
[root@chenc01 ~]# echo $$
1237
[root@chenc01 ~]# ps axjf | grep pts
  1090   1129   1129   1129 ?            -1 Ss       0   0:00  \_ sshd: root@pts/0 
  1129   1131   1131   1131 pts/0      1131 Ss+      0   0:00  |   \_ -bash
  1090   1188   1188   1188 ?            -1 Ss       0   0:00  \_ sshd: root@pts/1 
  1188   1190   1190   1190 pts/1      1246 Ss       0   0:00      \_ -bash
  1190   1237   1237   1190 pts/1      1246 S        0   0:00          \_ bash
  1237   1246   1246   1190 pts/1      1246 R+       0   0:00              \_ ps axjf
  1237   1247   1246   1190 pts/1      1246 S+       0   0:00              \_ grep pts
[root@chenc01 ~]# echo $VAR

[root@chenc01 ~]# exit
exit
[root@ chenc01 ~]# echo $VAR
123
[root@ chenc01 ~]# export VAR
[root@ chenc01 ~]# bash
[root@chenc01 ~]# echo $$
1248
[root@chenc01 ~]# ps axjf | grep pts
  1090   1129   1129   1129 ?            -1 Ss       0   0:00  \_ sshd: root@pts/0 
  1129   1131   1131   1131 pts/0      1131 Ss+      0   0:00  |   \_ -bash
  1090   1188   1188   1188 ?            -1 Ss       0   0:00  \_ sshd: root@pts/1 
  1188   1190   1190   1190 pts/1      1257 Ss       0   0:00      \_ -bash
  1190   1248   1248   1190 pts/1      1257 S        0   0:00          \_ bash
  1248   1257   1257   1190 pts/1      1257 R+       0   0:00              \_ ps axjf
  1248   1258   1257   1190 pts/1      1257 S+       0   0:00              \_ grep pts
[root@chenc01 ~]# echo $VAR
123
[root@chenc01 ~]# ps -ef|grep ssh
root       1090      1  0 11:18 ?        00:00:00 /usr/sbin/sshd 

ps axjf输出的第一列是PPID(父进程ID),第二列是PID(子进程ID)

当SSH连接Shell时,当前终端PPID(-bash)是sshd守护程序的PID(root@pts/0),因此在当前终端下的所有进程的PPID都是-bash的PID,比如执行命令、运行脚本。

所以当在-bash下设置的变量,只在-bash进程下有效,而-bash下的子进程bash是无效的,当export后才有效。

进一步说明:再重新连接SSH,去除上面定义的变量测试下

[root@ chenc01 ~]# ps -axjf | grep pts
Warning: bad syntax, perhaps a bogus '-'? See /usr/share/doc/procps-3.2.8/FAQ
  1090   1129   1129   1129 ?            -1 Ss       0   0:00  \_ sshd: root@pts/0 
  1129   1131   1131   1131 pts/0      1131 Ss+      0   0:00  |   \_ -bash
  1090   1188   1188   1188 ?            -1 Ss       0   0:00  \_ sshd: root@pts/1 
  1188   1190   1190   1190 pts/1      1278 Ss       0   0:00      \_ -bash
  1190   1278   1278   1190 pts/1      1278 R+       0   0:00          \_ ps -axjf
  1190   1279   1278   1190 pts/1      1278 S+       0   0:00          \_ grep --color=auto pts
[root@ chenc01 ~]# echo $$
1190
[root@ chenc01 ~]# VAR=123
[root@ chenc01 ~]# vim test.sh
[root@ chenc01 ~]# cat test.sh 
#!/bin/bash
ps -axjf | grep pts
echo $$
echo $VAR
[root@ chenc01 ~]# bash test.sh 
Warning: bad syntax, perhaps a bogus '-'? See /usr/share/doc/procps-3.2.8/FAQ
  1090   1129   1129   1129 ?            -1 Ss       0   0:00  \_ sshd: root@pts/0 
  1129   1131   1131   1131 pts/0      1131 Ss+      0   0:00  |   \_ -bash
  1090   1188   1188   1188 ?            -1 Ss       0   0:00  \_ sshd: root@pts/1 
  1188   1190   1190   1190 pts/1      1282 Ss       0   0:00      \_ -bash
  1190   1282   1282   1190 pts/1      1282 S+       0   0:00          \_ bash test.sh
  1282   1283   1282   1190 pts/1      1282 R+       0   0:00              \_ ps -axjf
  1282   1284   1282   1190 pts/1      1282 S+       0   0:00              \_ grep pts
1282
123
[root@ chenc01 ~]# export VAR
[root@ chenc01 ~]# bash test.sh 
Warning: bad syntax, perhaps a bogus '-'? See /usr/share/doc/procps-3.2.8/FAQ
  1090   1129   1129   1129 ?            -1 Ss       0   0:00  \_ sshd: root@pts/0 
  1129   1131   1131   1131 pts/0      1131 Ss+      0   0:00  |   \_ -bash
  1090   1188   1188   1188 ?            -1 Ss       0   0:00  \_ sshd: root@pts/1 
  1188   1190   1190   1190 pts/1      1285 Ss       0   0:00      \_ -bash
  1190   1285   1285   1190 pts/1      1285 S+       0   0:00          \_ bash test.sh
  1285   1286   1285   1190 pts/1      1285 R+       0   0:00              \_ ps -axjf
  1285   1287   1285   1190 pts/1      1285 S+       0   0:00              \_ grep pts
1285
123

所以在当前shell定义的变量一定要export,否则在写脚本时,会引用不到。

还需要注意的是退出终端后,所有用户定义的变量都会清除。

在/etc/profile下定义的变量就是这个原理,后面有章节会讲解Linux常用变量文件。

3、位置变量

位置变量指的是函数或脚本后跟的第n个参数。

1 − 1- 1n,需要注意的是从第10个开始要用花括号调用,例如${10}

shift可对位置变量控制,例如:

#!/bin/bash
echo "1: $1"
shift
echo "2: $2"
shift
echo "3: $3"
[root@ chenc01 ~]# bash a.sh a b c
1: a
2: c
3: 

每执行一次shift命令,位置变量个数就会减一,而变量值则提前一位。shift n,可设置向前移动n位。

4、特殊变量
$0脚本自身名字
$?返回上一条命令是否执行成功,0为执行成功,非0则为执行失败
$#位置参数总数
$*所有的位置参数被看做一个字符串
$@每个位置参数被看做独立的字符串
$$当前进程PID
$!上一条运行后台进程的PID

变量引用

赋值运算符示例
=变量赋值
+=两个变量相加
1、自定义变量与引用
[root@ chenc01 ~]# VAR=123
[root@ chenc01 ~]# echo $VAR
123
[root@ chenc01 ~]# VAR+=321
[root@ chenc01 ~]# echo $VAR
123321
Shell中所有变量引用使用$符,后跟变量名。

有时个别特殊字符会影响正常引用,那么需要使用${VAR},例如:

[root@ chenc01 ~]# VAR=123
[root@ chenc01 ~]# echo $VAR
123
[root@ chenc01 ~]# echo $VAR_  # Shell允许VAR_为变量名,所以此引用认为这是一个有效的变量名,故此返回空[root@ chenc01 ~]# echo ${VAR}
123

还有时候变量名与其他字符串紧碍着,也会误认为是整个变量:

[root@ chenc01 ~]# echo $VAR321

[root@ chenc01 ~]# echo ${VAR}321
123321
2、将命令结果作为变量值
[root@ chenc01 ~]# VAR=`echo 123`
[root@ chenc01 ~]# echo $VAR
123
[root@ chenc01 ~]# VAR=$(echo 123)
[root@ chenc01 ~]# echo $VAR
123
这里的反撇号等效于$(),都是用于执行Shell命令。

双引号和单引号

在变量赋值时,如果值有空格,Shell会把空格后面的字符串解释为命令:

[root@ chenc01 ~]# VAR=1 2 3
-bash: 2: command not found
[root@ chenc01 ~]# VAR="1 2 3"
[root@ chenc01 ~]# echo $VAR
1 2 3
[root@ chenc01 ~]# VAR='1 2 3'
[root@ chenc01 ~]# echo $VAR
1 2 3

看不出什么区别,再举个说明:

[root@ chenc01 ~]# N=3
[root@ chenc01 ~]# VAR="1 2 $N"
[root@ chenc01 ~]# echo $VAR
1 2 3
[root@ chenc01 ~]# VAR='1 2 $N'
[root@ chenc01 ~]# echo $VAR
1 2 $N

单引号是告诉Shell忽略特殊字符,而双引号则解释特殊符号原有的意义,比如$、!。

注释

Shell注释也很简单,只要在每行前面加个#号,即表示Shell忽略解释。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值