shell_01基本操作
什么是Shell
shell的念
shell是一个命令解释器
echo $SHELL --通过环境变量
cat /etc/shells--查看当前注册至系统的shell
shell的切换
1、临时切换
# /bin/ksh
2、固定切换
# vim /etc/passwd--文件中的最后一个字段
# chsh -s /sbin/nologin username
# usermod -s /bin/bash username
子shell 打开关闭
# /bin/bash
# bin/ksh
forks --复制进程信息,继承父shell的定义
exec --通过exec开启子shell
为什么使用shell
解决重复操作的作业
节约时间,提高工作效率
功能强大
不需要编译
shell脚本的基本元素
#!<命令解释器>
# --为注示
shell命令
流程控制(if/for/while/utile/case/function)
man BASH_BUILTINS
• shell的历史
• 常见的Shell
• Bourne Shell 最早出现的Shell的一种,大多数Unix的默认Shell,粗糙切缺乏任务控制
• nash-->initrd.img(init)
• not a shell , 它不是一个SHELL,是一个设计的尽可能小的简单命令解释器。主要用于初始化RAM DISK时候解释里面的linuxrc或者init这些简单的脚本
• csh
• 加州大学Berkeley分校作为其Unix实现的一部分而发展来的,目前最流行的交互式Shell。具有许多特性,比如任务控制、历史记录,但CShell不适合编写脚本,并有许多潜在的缺陷
• 臭名昭著的错误
• 用户不能进行文件描述符的处理
• 用户不能用任何恰当的方法将内部命令放在一起,通过管道也不可以
• 不可以将流控制和命令放在一起
• 某些命令看起来合理,可就是运行不了
• tcsh
• C shell的扩展版本,去除了C shell中臭名昭著的错误
• ksh
• Korn shell , 其与Bourne shell 兼容,并具备C shell的大部分特性,以及象历史编辑、重用旧命令并执行前编辑这些命令的能力。从对编程稳定性上它比csh可靠。
• bash
• Bourne-again shell, 由自由软件基金会开发,吸收了以上所有Shell好的特性,并被开源操作系统广泛使用
• 内部命令和外部命令
• Shell不需要启动一个单独的进程来运行内部命令
• Shell需要创建(fork)和执行(exec)一个新的子进程来运行外部命令
• 尽量使用内部命令有助于性能的提升
bash-->cd --解析内部命令的流程
bash-->forks-->bash(子进程)-->ls --解析外部命令的流程
# type ls --外部命令
ls is aliased to `ls --color=tty'
# type cd --内部命令
cd is a shell builtin
文件名
• 你可以用任何你认为合适的可见字符或不可见字符为文件或目录命名,但不要给自己找麻烦
• 从安全和方便角度
• 大小写字符
• 下划线
• 圆点
• 逗号
• 尽量不要出现“空格”
• 扩展名
• 方便分类,非必须
• 命令通过文件内结构判断其类型(file)
-type c
File is of type c:
b block (buffered) special
c character (unbuffered) special
d directory
p named pipe (FIFO)
f regular file
l symbolic link; this is never true if the -L option or the -fol-
low option is in effect, unless the symbolic link is broken.
If you want to search for symbolic links when -L is in effect,
use -xtype.
s socket
D door (Solaris)
通配符
• ? 任意单个字符,不能匹配空
• * 任意零个或多个字符组(不能匹配以点开头的文件)
• [ab] a或者b
• [a-z] a到z之间的任意字符,包括端点在内
• 是Shell 而非命令本身处理通配符,命令后的通配符会在命令执行前就被代换了
• 如果需要命令而非Shell处理通配符,请用“/"将通配符转义,跳脱字符
# ll /dev/sd?
brw-r----- 1 root disk 8, 0 03-14 09:03 /dev/sda
# ll /dev/sd*
-rw-r--r-- 1 root root 0 03-14 11:30 /dev/sd
brw-r----- 1 root disk 8, 0 03-14 09:03 /dev/sda
brw-r----- 1 root disk 8, 1 03-14 09:03 /dev/sda1
brw-r----- 1 root disk 8, 2 03-14 09:03 /dev/sda2
brw-r----- 1 root disk 8, 3 03-14 09:03 /dev/sda3
brw-r----- 1 root disk 8, 4 03-14 09:03 /dev/sda4
brw-r----- 1 root disk 8, 5 03-14 09:03 /dev/sda5
# ll /dev/sd?[1-5]
brw-r----- 1 root disk 8, 1 03-14 09:03 /dev/sda1
brw-r----- 1 root disk 8, 2 03-14 09:03 /dev/sda2
brw-r----- 1 root disk 8, 3 03-14 09:03 /dev/sda3
brw-r----- 1 root disk 8, 4 03-14 09:03 /dev/sda4
brw-r----- 1 root disk 8, 5 03-14 09:03 /dev/sda5
# ll /dev/tty[1-5][0-9]
# ll /dev/sda[13]
brw-r----- 1 root disk 8, 1 03-14 09:03 /dev/sda1
brw-r----- 1 root disk 8, 3 03-14 09:03 /dev/sda3
# ll /dev/sda[1-3]
brw-r----- 1 root disk 8, 1 03-14 09:03 /dev/sda1
brw-r----- 1 root disk 8, 2 03-14 09:03 /dev/sda2
brw-r----- 1 root disk 8, 3 03-14 09:03 /dev/sda3
转义
# touch test/*/?/[/].sh
跳脱字符
# ls /
> /root/
> a/
> /b
bash中的引号:
双引号 “ ” :允许通过$符号引用其他变量值,会把引号的内容当成整体来看待
单引号 ‘ ’ :禁止引用其他变量值,shell中特殊符号都被视为普通字符,会把引号的内容当成整体来看待
反撇号 `` :
$() 在执行命令的过程中会优先执行
; 可对一行命令进行分割,在执行过程中不考虑上一个命令执行是否是正确的
&& 可对一行命令进行分割,在执行过程中考虑上一个命令执行是否是正确的
||
! 命令历史
# echo "This system is "HOSTNAME""
This is system is HOSTNAME
# echo "This system is "$HISTNAME""
This is system is
# echo "This system is "$HOSTNAME""
This is system is desktop8.example.com
# echo 'This system is "$HOSTNAME"'
This is system is "$HOSTNAME"
[root@desktop8 ~]# echo $5.00
.00
[root@desktop8 ~]# echo /$5.00
$5.00
# host=`ifconfig eth0 |grep 'inet addr'|cut -d : -f2|cut -d ' ' -f1`
# host2=$(ifconfig eth0 |grep 'inet addr'|cut -d : -f2|cut -d ' ' -f1)
$(()) :运算符
$[]
# a=$((1 + 10))
# echo $a
# a=$[1 + 100]
# echo $a
• shell的配置文件(软件+配置文件)
• csh
• $HOME/.cshrc
• 登录时执行$HOME/.login
• 登出时执行$HOME/.logout
• bash
用户加载shell配置流程:
# user01-->login-->bash-->/etc/profile-->$HOME/.bash_profile-->$HOME/.bashrc-->/etc/bashrc
全局配置文件:
/etc/profile --bash工作环境的配置(环境变量)
/etc/profile.d/*.sh --/etc/profile的扩展配置文件
/etc/bashrc --bash的配置文件
针对每个用户的配置文件:
$HOME/.bash_history --存放命令历史
$HOME/.bash_logout --注销/退出shell的时候执行的脚本
$HOME/.bash_profile
$HOME/.bashrc
命令的编辑
ctrl + u --删除当前光标至行首内容
ctrl + k --删除当前光标至行尾内容
ctrl + c --中断
ctrl + l --清屏
ctrl + a --跳到行首HOME
crtl + e --路到行尾END
ctrl + r --快速搜索history命令
ctrl + z --转入后台运行 fg bg
Ctrl + d --退出shell,logout
↑(Ctrl+p) 显示上一条命令
↓(Ctrl+n) 显示下一条命令
alias --查询系统中所有已经存在的别名
alias 别名=‘真名’
unalias --取消系统中的别名
unalias 别名
unalias -a 删除所有的别名
临时:
alias la='ls -a'
固定:
可以写至以下文件,定义完成需要使用source来刷新,或者注销重新登录用户:
/etc/profile
$HOME/.bash_profile
$HOME/.bashrc
/etc/bashrc
/etc/profile.d/*.sh
命令历史:
HISTSIZE=1000 设置命令历史的条数
history 查询当前用户用过的所有命令历史(内存)
cat $/HOME/.bash_history | grep xx(硬盘)
history -w 同步内存中的命令至硬盘($/HOME/.bash_history)
自动同步:exit/注销
history -c
echo "" > $HOME/bash_history--清空命令历史
# :> $HOME/bash_history
调用命令历史:
!101 通过编号
!! 调用最后一条命令历史
!vim 调用离我最近一条以vim开头的命令历史
!$ 调用最后一条命令历史中的参数
命令字 + [选项] + 参数
ls -l /
ctrl + r 查找命令历史
bash的特殊符号:
< << > >> &> |
标准输入 0
标准正确输出(屏幕) 1
错误输出 (屏幕) 2
# ls -l /dev/std*
lrwxrwxrwx. 1 root root 15 Aug 3 09:34 /dev/stderr -> /proc/self/fd/2
lrwxrwxrwx. 1 root root 15 Aug 3 09:34 /dev/stdin -> /proc/self/fd/0
lrwxrwxrwx. 1 root root 15 Aug 3 09:34 /dev/stdout -> /proc/self/fd/1
<<herestring --非交互模式进行输入追加重定向
# cat > a3.txt <<END
> gfdsjkgfdjgkldf
> fdsfdsfds
> fdsfdsf
> END
> --输出覆盖重定向
>> --输出追加重定向
2> --错误覆盖输出重定向
2>> --错误追加输出重定向
&> --输出正确/错误重定向
&>> --RHEL6可以实现正确和错误追加重定向。
>> --- 2>&1 rhel5
# cat /root/a2.txt /root &> a.txt --将正确和错误一起覆盖重定向至a.txt
cat /root/a2.txt /root >> a.txt 2>&1 --将正确和错误一起追加重定向至a.txt
[root@i ~]# ls /ttttt /etc/passwd- >1.txt 2>2.txt && &>3.txt
| 管道
cat /etc/passwd |grep root |grep ^root
--把passwd输出结果通过管道交给第二个命令去处理,往后的以此类推
• bash shell的基本变量和使用
变量的设置
引用
作用域
删除变量
• 设置变量
• VARNAME=VAR_VALUE--变量名中的字母建议大写
--变量名起始字符不能是数据或者特殊符号
变量名 变量值
• readonly VARNAME--设置只读变量,不能删除不能更改
• read --通过断点设置变量
• read -p "请输入一个值(数字):" a
read -t 5 "请输入一个值:"IP
--设置赋值的超时时间。
#H=192.168.0.253
#echo $H
192.168.0.253
#read -p "Please enter ip address: " H2
Please enter ip address: 192.168.0.252
#echo $H2
192.168.0.252
• 引用变量
• echo $VARNAME
• echo ${VARNAME}
作用域
• 全局变量(父子shell)
• export
• . 或 source 调用
• 局部变量
• 程序内变量
• 函数内变量
删除变量:
• unset VARNAME
用户自定义变量:
host=192.168.0.1
ping $host
环境变量 --(用户工作环境)
set --都可以查,但set还可以显示用户自定义变量
env --查看环境变量
PATH
• 用户命令搜索路径
PWD
用户当前目录的绝对路径
HOME
• 包含用户主目录的绝对路径
SHELL
• 用户登录shell的绝对路径
USER或LOGNAME
• 用户名,在登录后自动设置并不会改变
PS1
• 主提示符配置变量 # PS1="[/u@/H /t /w]/$"
PS2
• 复合命令提示符配置变量
PS1和PS2
提示符变量,用于设置提示符格式
PS1是用于设置一级Shell提示符的环境变量,也称为主提示符字符串,即改变: [root @jselab ~]#
PS1变量是[/u@/h /W]/$,/u、/h、/W和/$表示了特定含义,/u表示当前用户名,/h表示表示主机名,/W表示当前目录名,如果是root用户,/$表示#号,其他用户,/$则表示$号
PS2是用于设置二级Shell提示符的环境变量
/d 以“周 月 日”格式显示的日期
/H 主机名和域名
/h 主机名
/s Shell的类型名称
/T 以12小时制显示时间,格式为:HH:MM:SS
/t 以24小时制显示时间,格式为:HH:MM:SS
/@ 以12小时制显示时间,格式为:am/pm
/u 当前的用户名
/v bash Shell的版本号
/V bash Shell的版本号和补丁号
/w 当前工作目录的完整路径
/W 当前工作目录名字
/# 当前命令的序列号
/$ 如果UID为0,打印#;否则,打印$
内置bash中变量
$#:命令行中位置变量的个数
$*:所有位置变量的内容
$@: 所有位置参数的内容,与$*的分割任不一样,建议和所有的位置参数时使用这种方式。
$?:上一条命令执行后返回的状态,当返回状态值为0时表示执行正常,非0值表示执行异常或出错
$$:当前所在进程的进程号
$!:后台运行的最后一个进程号
$0:当前执行的进程/程序名
# ls &> /dev/null && echo YES
YES
# fdsfds &> /dev/null && echo YES --无返值
位置变量:
• $0~$9,${10} $* $#等使用和循环选取
#!/bin/bash
echo "/$0 = $0 "
echo "/$1 = $1 "
echo "/$2 = $2 "
echo "/$3 = $3 "
echo "/$4 = $4 "
echo "/$5 = $5 "
echo "/$6 = $6 "
echo "/$7 = $7 "
echo "/$8 = $8 "
echo "/$9 = $9 "
echo "/$10 = ${10} "
echo "/$11 = ${11} "
echo "/$* = $* "
echo "/$# = $# "
• $0~$9 位置参数变量
• ${10}~${n} 扩展位置参数变量
#./aa.sh 1 2 3 4 5 6 7 8
$0 = ./aa.sh
$1 = 1
$2 = 2
$3 = 3
$4 = 4
$5 = 5
$6 = 6
$7 = 7
$8 = 8
$9 =
$10 =
$11 =
$* = 1 2 3 4 5 6 7 8
$# = 8
有类型变量
• 默认bash将变量设置为文本值,当使用算数方法时会自动将其转换为整数值
• 内置命令declare可以修改变量属性
• declare参数
-a 将变量看成数组
-f 只使用函数名
-F 显示未定义的函数名
-i 将变量看成整数
-r 使变量只读
-x 标记变量通过环境导出
-r:
# h=192.168.0.1
# declare -r h
等同于:
# readonly h
-x:
# H=192.168.0.100
# declare -x H
# export --可以查询所有全局变量
-i
• 例子
# varA=3
# varB=7
# result_out=varA*varB
# echo $result_out
varA*varB
# declare -i varC=3 varD=7
# declare -i declare_result_out
# declare_result_out=varC*varD
# echo $declare_result_out
21
• 数组
• 数组类似于保存取值的一个排列
排列中每个位置称为元素
每个元素通过数字下标访问
• 数组元素可以包含字符串或数字
• 数组下标从0开始
• 数组可以使用 declare a 来显示声明, 数组下标的范围没有任何限制 , 同时也不必使用连续的分量。可以通过 ${ array [i]}. 访问数组中的元素。如果不指定元素,则表示第一个元素。 @ 与 * 相同,但是使用时加引号,并在引号中返回每个参数, *则作为一个整体的字符串返回。
(1) name = (value1 ... valuen) 此时下标从 0 开始,也可以: names=([2]=alice [0]=hatter [1]=duchess)。
(2) name[index] = value
# A=(a b c def)
# echo ${A[@]}
a b c def
# echo ${A}
a
echo ${A[*]}
a b c def
for i in "${A[@]}"; do
echo $i
done
显示的结果:
a
b
c
def
for i in "${A[*]}"; do
echo $i
done
显示结果:
a b c def
// 清除变量
$ unset A
$ echo ${A[@]}
$
A=B
B=C
unset $A 事实上所取消的变量是 B 而不是 A
// 清空变量 , 即将值变为空
$ A=
$ echo ${A[@]}
$
脚本执行:
1、脚本无可执行权限:
# /bin/sh /xx/xx.sh--开启一个新的子shell去执行脚本,脚本不需要可执行权限
# /bin/bash /xx/xx.sh
# source /xx/xx.sh--强制在当前的shell执行脚本
# . /xx/xx.sh
2、脚本拥有可执行权限
# chmod +x /xx/xx.sh
# /xx/xx.sh