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