Shell知识总结
Shell概念
- Shell概念:Shell 是一个应用程序,它连接了用户和 Linux 内核,让用户能够更加高效、安全、低成本地使用 Linux 内核,这就是 Shell 的本质。
编译与解释
- 编译:有的编程语言,如 C/C++、Pascal、Go语言、汇编等,必须在程序运行之前将所有代码都翻译成二进制形式,也就是生成可执行文件,用户拿到的是最终生成的可执行文件,看不到源码。这个过程叫做编译,这样的编程语言叫做编译型语言,完成编译过程的软件叫做编译器。
- 编译型语言的优点:执行速度快、对硬件要求低、保密性好,适合开发操作系统、大型应用程序、数据库等。
- 解释:有的编程语言,如 Shell、JavaScript、Python、PHP等,需要一边执行一边翻译,不会生成任何可执行文件,用户必须拿到源码才能运行程序。程序运行后会即时翻译,翻译完一部分执行一部分,不用等到所有代码都翻译完。这个过程叫做解释,这样的编程语言叫做解释型语言或者脚本语言,完成解释过程的软件叫做解释器。
常见Shell
- sh:Bourne shell
- csh: C shell
- tcsh:C shell的增强版
- ash:一个简单的轻量级的 Shell,占用资源少,适合运行于低内存环境,但与 bash shell 完全兼容。
- bash:bash shell 是 Linux 的默认 shell,保持了对 sh shell 的兼容性,bash 兼容 sh 意味着,针对 sh 编写的 Shell 代码可以不加修改地在 bash 中运行。
bash 和 sh 还有一些不同之处:一方面,bash 扩展了一些命令和参数;另一方面,bash 并不完全和 sh 兼容,它们有些行为并不一致,但在大多数企业运维的情况下区别不大,特殊场景可以使用 bash 代替 sh。
查看Shell
- Shell程序目录:一般放在
/bin或者/usr/bin目录下,Linux系统中这些可用的Shell程序目录都记录在/etc/shells文件中,使用cat /etc/shells命令可以打开查看。
在现代的 Linux 上,sh 已经被 bash 代替,
/bin/sh往往是指向/bin/bash的符号链接。
- 查看当前 Linux 的默认 Shell:
echo $SHELL。
进入Shell的两种方式
- 进入Linux控制台的方式:一种进入 Shell 的方法是让 Linux 系统退出图形界面模式,进入控制台模式,按下
Ctrl + Alt + Fn(n=1,2,3,4,5...)快捷键就可以来回切换。
例如,CentOS 在启动时会创建 6 个虚拟控制台,按下快捷键
Ctrl + Alt + Fn(n=2,3,4,5,6)可以从图形界面模式切换到控制台模式,按下Ctrl + Alt + F1可以从控制台模式再切换回图形界面模式。也就是说,1 号控制台被图形桌面程序占用了。
- Debian下使用Ctrl + Alt +F7切换回图形界面模式
- 使用终端的方式:在图形界面中可以右键进入终端。
Shell命令的基本格式
-
基本格式:
command [选项] [参数],其中[]表示可选的,即有些命令不写选项和参数也能执行,有些命令在必要的时候可以附带选项和参数。 -
短格式选项和长格式选项:
- 短格式选项是长格式选项的简写,用一个减号
-和一个字母表示,例如ls -l。 - 长格式选项是完整的英文单词,用两个减号
--和一个单词表示,例如ls --all。
- 短格式选项是长格式选项的简写,用一个减号
Shell命令的本质
- Shell命令分为两种:内置命令、外置命令。
- 内置命令:内置命令不宜过多,Shell 是一个常驻内存的程序,占用过多内存会影响其它的程序。
- 外部命令:将可执行程序的路径提供给Shell即可执行外部命令。为了更方便检索到外部命令的路径,Shell 在启动文件中增加了一个叫做 PATH 的环境变量,该变量保存了 Shell 对外部命令的查找路径,如果在这些路径下找不到同名的文件,就直接报错。
Shell脚本
-
Shell脚本示例:
#!/bin/bash echo "hello world!" echo "please input your name!" read name echo "hello, $name" -
执行Shell脚本:
- 使用
chmod +x给 test.sh 增加执行权限,chmod +x ./test.sh。 ./test.sh。
也可以直接执行
source test.sh,不需要增加权限,也不需要./。另外,如果需要在新进程中运行 Shell 脚本,可以使用bash test.sh这种写法;如果在当前进程中运行 Shell 脚本,可使用. ./test.sh`这种写法。 - 使用
-
输出进程PID:使用
$$变量就可以获取当前进程的 PID,$$是 Shell 中的特殊变量,即echo $$。
Shell变量
在 Bash shell 中,每一个变量的值都是字符串,这意味着Bash shell 在默认情况下不会区分变量类型,即使你将整数和小数赋值给变量,它们也会被视为字符串。
-
定义变量:
- 规则:
- 变量名由数字、字母、下划线组成;
- 必须以字母或者下划线开头;
- 不能使用 Shell 里的关键字(通过 help 命令可以查看保留关键字)。
- 定义方式:
- variable=value
- variable='value'
- variable="value"
- 规则:
-
使用变量:使用变量时,变量名外面的花括号
{ }是可选的,加花括号可帮助解释器识别变量的边界。 -
删除变量:
unset variable_name,但unset命令不可以删除只读变量,只读变量不能被修改。 -
Shell变量作用域:
-
局部变量:只能在函数内部使用;
-
全局变量:可以在当前 Shell 进程中使用,在 Shell 中定义的变量,默认就是全局变量。全局变量的作用范围是当前的 Shell 进程,而不是当前的 Shell 脚本文件,若新开启一个Shell会话,不同Shell会话之间的变量不共享。
Shell 函数中定义的变量默认是全局变量,它和在函数外部定义变量拥有一样的效果。
-
环境变量:可以在子进程中使用。
-
单引号与双引号的区别
-
以单引号
' '包围变量的值时,单引号里面是什么就输出什么,即使内容中有变量和命令(命令需要反引起来)也会把它们原样输出。这种方式比较适合定义显示纯字符串的情况,即不希望解析变量、命令等的场景。 -
以双引号
" "包围变量的值时,输出时会先解析里面的变量和命令,而不是把双引号中的变量名和命令原样输出。这种方式比较适合字符串中附带有变量和命令并且想将其解析后再输出的变量定义。如果变量的内容是数字,那么可以不加引号;
如果真的需要原样输出就加单引号;
其他没有特别要求的字符串等最好都加上双引号,不加双引号的字符串出现变量时也会被解析。
将命令的结果复制给变量
- Shell通过以下两种方式将命令的执行结果赋值给变量:
- 把命令用反引号
(位于 Esc 键的下方)包围起来,反引号和单引号非常相似,容易产生混淆,不推荐; - 把命令用
$()包围起来,区分更加明显,推荐。
- 把命令用反引号
date命令
-
获取当前系统时间:
#!/bin/bash begin_time=`date` #开始时间,使用``替换 sleep 20s #休眠20秒 finish_time=$(date) #结束时间,使用$()替换 echo "Begin time: $begin_time" echo "Finish time: $finish_time" -
date时间域:
$(date +%y%m%d)。-
% H 小时(00..23)
-
% I 小时(01..12)
-
% k 小时(0..23)
-
% l 小时(1..12)
-
% M 分(00..59)
-
% p 显示出AM或PM
-
% r 时间(hh:mm:ss AM或PM),12小时
-
% s 从1970年1月1日00:00:00到目前经历的秒数
-
% S 秒(00..59)
-
% T 时间(24小时制)(hh:mm:ss)
-
% X 显示时间的格式(%H:%M:%S)
-
% Z 时区 日期域
-
% a 星期几的简称( Sun..Sat)
-
% A 星期几的全称( Sunday..Saturday)
-
% b 月的简称(Jan..Dec)
-
% B 月的全称(January..December)
-
% c 日期和时间( Mon Nov 8 14:12:46 CST 1999)
-
% d 一个月的第几天(01..31)
-
% D 日期(mm/dd/yy)
-
% h 和%b选项相同
-
% j 一年的第几天(001..366)
-
% m 月(01..12)
-
% w 一个星期的第几天(0代表星期天)
-
% W 一年的第几个星期(00..53,星期一为第一天)
-
% x 显示日期的格式(mm/dd/yy)
-
% y 年的最后两个数字( 1999则是99)
-
% Y 年(例如:1970,1996等)
-
-
获取UNIX时间戳:
-
UNIX 时间戳:指从 1970 年 1 月 1 日 00:00:00 到目前为止的秒数。
-
获取方式:使用 data 命令的
%s格式控制符可以得到当前的 UNIX 时间戳。 -
#!/bin/bash begin_time=`date +%s` #开始时间,使用``替换 sleep 20s #休眠20秒 finish_time=$(date +%s) #结束时间,使用$()替换 run_time=$((finish_time - begin_time)) #时间差 echo "begin time: $begin_time" echo "finish time: $finish_time" echo "run time: ${run_time}s"
-
第 6 行代码中的
(( ))是 Shell 数学计算命令。在 Shell 中进行数据计算必须使用专门的数学计算命令,(( ))就是其中之一。
位置参数/命令行参数
-
背景:
- 运行 Shell 脚本文件时我们可以给它传递一些参数,这些参数在脚本文件内部可以使用
$n的形式来接收,例如,$1表示第一个参数,$2表示第二个参数,依次类推。 - 同样,在调用函数时也可以传递参数。Shell 函数参数的传递和其它编程语言不同,没有所谓的形参和实参,在定义函数时也不用指明参数的名字和数目。换句话说,定义 Shell 函数时不能带参数,但是在调用函数时却可以传递参数,这些传递进来的参数,在函数内部就也使用
$n的形式接收。
- 运行 Shell 脚本文件时我们可以给它传递一些参数,这些参数在脚本文件内部可以使用
-
示例:
#!/bin/bash #定义函数 function func(){ echo "Language: $1" echo "URL: $2" } #调用函数 func C++ http://c.biancheng.net/cplus/除了 $n,Shell 中还有 $#、$*、$@、$?、$$ 几个特殊参数。
-
Shell 特殊变量及其含义:
| 变量 | 含义 |
|---|---|
$0 |
当前脚本的文件名。 |
$n(n≥1) |
传递给脚本或函数的参数。n 是一个数字,表示第几个参数。 |
$# |
传递给脚本或函数的参数个数。 |
$* |
传递给脚本或函数的所有参数。 |
$@ |
传递给脚本或函数的所有参数。当被双引号" "包含时,$@ 与 $* 稍有不同。 |
$? |
上个命令的退出状态,或函数的返回值。 |
$$ |
当前 Shell 进程 ID。对于 Shell 脚本,就是这些脚本所在的进程 ID。 |
$*和$@之间的区别:- 当
$*和$@不被双引号" "包围时,它们之间没有任何区别。 - 当它们被双引号
" "包含时,就有区别:"$*"会将所有的参数从整体上看做一份数据,而不是把每个参数都看做一份数据。"$@"仍然将每个参数都看作一份数据,彼此之间是独立的。
获取字符串长度
-
方法:
${#string_name}。 -
代码示例:
#!/bin/bash str="http://c.biancheng.net/shell/" echo ${#str}
字符串拼接
-
方法:将两个字符串并排放在一起就能实现拼接。
-
代码示例:
#!/bin/bash name="Shell" url="http://c.biancheng.net/shell/" str1=$name$url #中间不能有空格 str2="$name $url" #如果被双引号包围,那么中间可以有空格 str3=$name": "$url #中间可以出现别的字符串 str4="$name: $url" #这样写也可以 str5="${name}Script: ${url}index.html" #这个时候需要给变量名加上大括号 #运行结果 #Shellhttp://c.biancheng.net/shell/ #Shell http://c.biancheng.net/shell/ #Shell: http://c.biancheng.net/shell/ #Shell: http://c.biancheng.net/shell/ #ShellScript: http://c.biancheng.net/shell/index.html
字符串截取
-
多种截取方法:
格式 说明 ${string: start :length}从 string 字符串的左边第 start 个字符开始,向右截取 length 个字符。 ${string: start}从 string 字符串的左边第 start 个字符开始截取,直到最后。 ${string: 0-start :length}从 string 字符串的右边第 start 个字符开始,向右截取 length 个字符。 ${string: 0-start}从 string 字符串的右边第 start 个字符开始截取,直到最后。 ${string#*chars}从 string 字符串第一次出现 *chars的位置开始,截取*chars右边的所有字符。${string##*chars}从 string 字符串最后一次出现 *chars的位置开始,截取*chars右边的所有字符。${string%*chars}从 string 字符串第一次出现 *chars的位置开始,截取*chars左边的所有字符。${string%%*chars}从 string 字符串最后一次出现 *chars的位置开始,截取*chars左边的所有字符。
函数
-
函数定义格式:
function name() { #如果写了 function 关键字,也可以省略函数名后面的小括号function name{ statements [return value] } #也可以不写function关键字 name() { statements [return value] }
浙公网安备 33010602011771号