特點:1 shell變量沒有數據類型的區分
2 Shell 把任何存儲在變量中的值,皆視為以字符組成的“字符串”。
3 設定的變量值只在當前shell環境中有作用
4 不能以數字開頭
5 =號兩邊不能存在空格
6 若變量值中存在空格,必須用括號將變量值括起來 I = “Jack Black”
在編寫shell時,如果變量未賦值,后續使用時不會出現任何錯誤。如果要顯示錯誤提示,則需要命令 shopt -s -o nounset
shopt -s -o nounset解析如下
.范例如下
[root@localhost ~]# vim test1.sh #!/bin/bash echo $Infomix [root@localhost ~]# sh test1.sh # 未提示任何錯誤 [root@localhost ~]# vim test1.sh [root@localhost ~]# vim test1.sh #!/bin/bash shopt -s -o nounset #添加錯誤提示 echo $Infomix [root@localhost ~]# sh test1.sh test1.sh:行4: Infomix: 為綁定變量 #提示錯誤
二 取得變量值
$變量名稱=${變量名稱}
如果變量作為字符的一部分輸出時,則必須用${}將變量括起來,否則shell將無法識別變量。$會將后面的所有字符當做變量的一部分,肯定是找不到變量的
[root@localhost ~]# myname='lsq' [root@localhost ~]# echo $myname lsq [root@localhost ~]# echo ${myname} lsq [root@localhost ~]# echo hello${myname}boy hellolsqboy [root@localhost ~]# echo hello$mynameboy hello
如果后面接的不是字符,也不是_下划線,則不需要{}來括起來。變量后接中文也是可以的。呵呵。
[root@localhost ~]# dir2=sbin [root@localhost ~]# echo /usr/local/$dir2/config /usr/local/sbin/config
$是去變量值的特殊字符,如果要顯示$怎么操作,轉義字符 \ 或者用單引號括起來 '$i'
Bash除了echo之外,還提供了一個c類似的printf的語法。感覺這個東西有字符串格式化的意思。體會一下
%s 以字符串的形式顯示變量值
[root@localhost ~]# printf "%s" "$dir2" sbin[root@localhost ~]# printf "%s\n" "$dir2" sbin #\n和c語言一樣,都是換行的意思。 [root@localhost ~]#
[root@localhost ~]# SP='ABC 123 XYZ' [root@localhost ~]# printf "%q\n" "$SP" ABC\ 123\ XYZ #%q會將變量值中的特殊字符,用\字符轉義,實例中就是在空格前加\
三 取消與清空變量
unset 變量名
unset -v 變量名 -v 表示取消的是變量
unset -f 函數名 -f 表示取消的是函數
清空變量值
變量名= 跟unset的區別是,清空變量值,該變量還存在,只不過值變成空而已。unset則會將變量銷毀
四 變量和引號
雙引號和單引號的區別
前邊說過,變量賦值可以用單引號或者雙引號,但是二者是有區別的
雙引號相對於單引號可以有如下操作
1 替換變量 例
[root@localhost shellscript]# vim test2.sh #! /bin/bash shopt -s -o nounset myname="Bash shell" #echo $myname hello="hello ,i am $myname" echo $hello [root@localhost shellscript]# sh test2.sh hello ,i am Bash shell #將變量名myname用Bash shell 進行了替換
#但是如果我們用單引號
[root@localhost shellscript]# vim test2.sh
#! /bin/bash
shopt -s -o nounset
myname="Bash shell"
#echo $myname
#hello="hello ,i am $myname"
hello='hello ,i am ,$myname'
echo $hello
[root@localhost shellscript]# sh test2.sh
hello ,i am ,$myname #看到了么?他不會替換,他會將變量名整體輸出
如果要在雙引號中輸出變量名而非替換,則需要用到\轉義字符轉義
2 替換命令執行結果
3 替換算數運算結果
四 變量的有效范圍
變量的有效范圍就是當前所處的shell環境
如果要讓變量在所有的shell都執行,那就需要將該變量設置成環境變量
通過 export 命令就可以將變量設置成環境變量。
export testVar="hello world" 或 testVar="hello world" export testVar
取消環境變量
testVar=
或者
unset testVar
五 Bash 的內置變量
六 設置只讀變量
readonly 命令和declare -r 命令
readonly 或 readonly -p 列出只讀屬性的變量列表
readonly -f 函數名 設置該函數不可修改
readonly -a 數組變量 設置后該數組為只讀數組
例
s[0]=10 s[1]=20 s[2]=30 readonly -a s #設置該數組為只讀數組 s[3]=50 該行 會報錯
調整變量的其他屬性
[root@localhost ~]# declare -i I=60 #設定該變量為整數變量 [root@localhost ~]# echo $I 60 [root@localhost ~]# I="test" #如果傳入字符串,則會將該變量變為0 [root@localhost ~]# echo $I 0 [root@localhost ~]#
七 取別名
alias 變量名
[root@localhost ~]# alias -p #列出別名列表 alias cp='cp -i' alias egrep='egrep --color=auto' alias fgrep='fgrep --color=auto' alias grep='grep --color=auto' alias l.='ls -d .* --color=auto' alias ll='ls -l --color=auto' alias ls='ls --color=auto' alias mv='mv -i' alias perlll='eval `perl -Mlocal::lib`' alias rm='rm -i' alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
alias 別名=指令 注意:=號兩邊不允許有空格。 如需要有空格,必須用括號括起來。如上例中alias l.='ls -d .*'
unalias 取消別名
八 自定義工作環境
以一般賬號的角色工作時,默認的工作環境配置文件為
這里的~目錄,一般指的是家目錄
自定義工作環境的意義:讓用戶登錄主機時,能擁有安全及易於執行命令的環境。包括 建立文件的權限 命令搜尋路徑 環境變量 命令提示符 別名 喜好比較器 顯示文件使用的顏色等
[root@localhost ~]# cd /root [root@localhost ~]# cat .bash_profile #這個是root的默認配置文件 # .bash_profile # Get the aliases and functions if [ -f ~/.bashrc ]; then . ~/.bashrc fi # User specific environment and startup programs PATH=$PATH:$HOME/bin export PATH
[root@localhost /]# cd home #這個是普通用戶的配置文件,普通用戶在家目錄 /home目錄中 [root@localhost home]# ls ftptest lsq [root@localhost home]# cd lsq [root@localhost lsq]# cat .bash_profile # .bash_profile # Get the aliases and functions if [ -f ~/.bashrc ]; then . ~/.bashrc fi # User specific environment and startup programs PATH=$PATH:$HOME/.local/bin:$HOME/bin export PATH
管理員維護的環境配置文件一般有三個 /etc/profile /etc/bashrc /etc/skel目錄下的文件
其中 /etc/profile和/etc/bashrc中的設定,會影響所有賬號的使用環境。
在/etc/profile中,通常會設定 umask,PATH,多國語言環境,提示符號,別名等
這是我本機的profile
[root@localhost etc]# cat profile # /etc/profile # System wide environment and startup programs, for login setup # Functions and aliases go in /etc/bashrc # It's NOT a good idea to change this file unless you know what you # are doing. It's much better to create a custom.sh shell script in # /etc/profile.d/ to make custom changes to your environment, as this # will prevent the need for merging in future updates. pathmunge () { case ":${PATH}:" in *:"$1":*) ;; *) if [ "$2" = "after" ] ; then PATH=$PATH:$1 else PATH=$1:$PATH fi esac } if [ -x /usr/bin/id ]; then if [ -z "$EUID" ]; then # ksh workaround EUID=`/usr/bin/id -u` UID=`/usr/bin/id -ru` fi USER="`/usr/bin/id -un`" LOGNAME=$USER MAIL="/var/spool/mail/$USER" fi # Path manipulation if [ "$EUID" = "0" ]; then pathmunge /usr/sbin pathmunge /usr/local/sbin else pathmunge /usr/local/sbin after pathmunge /usr/sbin after fi HOSTNAME=`/usr/bin/hostname 2>/dev/null` HISTSIZE=1000 if [ "$HISTCONTROL" = "ignorespace" ] ; then export HISTCONTROL=ignoreboth else export HISTCONTROL=ignoredups fi export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE HISTCONTROL # By default, we want umask to get set. This sets it for login shell # Current threshold for system reserved uid/gids is 200 # You could check uidgid reservation validity in # /usr/share/doc/setup-*/uidgid file if [ $UID -gt 199 ] && [ "`/usr/bin/id -gn`" = "`/usr/bin/id -un`" ]; then umask 002 else umask 022 fi for i in /etc/profile.d/*.sh /etc/profile.d/sh.local ; do if [ -r "$i" ]; then if [ "${-#*i}" != "$-" ]; then . "$i" else . "$i" >/dev/null fi fi done unset i unset -f pathmunge
一下是本機普通用戶的配置環境,在/etc/skel目錄中
[root@localhost ~]# cd /etc/skel [root@localhost skel]# ls [root@localhost skel]# ls -la 總用量 28 drwxr-xr-x. 3 root root 78 4月 11 2018 . drwxr-xr-x. 162 root root 12288 10月 14 15:36 .. -rw-r--r--. 1 root root 18 10月 31 2018 .bash_logout -rw-r--r--. 1 root root 193 10月 31 2018 .bash_profile -rw-r--r--. 1 root root 231 10月 31 2018 .bashrc drwxr-xr-x. 4 root root 39 8月 19 11:00 .mozilla [root@localhost skel]# cat .bash_profile # .bash_profile # Get the aliases and functions if [ -f ~/.bashrc ]; then . ~/.bashrc fi # User specific environment and startup programs PATH=$PATH:$HOME/.local/bin:$HOME/bin export PATH [root@localhost skel]# cat .bashrc # .bashrc # Source global definitions if [ -f /etc/bashrc ]; then . /etc/bashrc fi # Uncomment the following line if you don't like systemctl's auto-paging feature: # export SYSTEMD_PAGER= # User specific aliases and functions [root@localhost skel]# cat .bash_logout # ~/.bash_logout
九 數組
bash數組的特點: 1 沒有個數限制 2 可以跳躍賦值 3 所以可以表達式表示,如1+2 4 bash只支持一維數組
[root@localhost ~]# A[0]=5 [root@localhost ~]# A[1]=10 [root@localhost ~]# A[2]=28 [root@localhost ~]# A[3]="bash shell"
[root@localhost ~]# echo $A
5
[root@localhost ~]# echo $A[0] 看出跟上一句的區別了么?他走的是C語言的路子,讀取$A直接取得是數組首地址的值,如果要取數組剩余標的值,就需要下面的操作.也就是將整個數組包含小標用大括號括起來,表示一個整體變量,用$讀出 5[0] [root@localhost ~]# echo $(A[0]) bash: A[0]: 未找到命令... [root@localhost ~]# echo ${A[0]} #這里要注意一下,取數組值的時候,用到的是{}大括號 5 [root@localhost ~]# echo ${A[1+1]} 28 [root@localhost ~]# B={23 88 99 66} bash: 88: 未找到命令... [root@localhost ~]# B=(23 88 99 66) #數組群體賦值的時候,用到的是()小括號。這點要注意 [root@localhost ~]# echo ${B[0]} 23
正因為,shell數組沒有個數的限制,也就是說,不需要在使用數組的時候,首先要固定一下數組的長度,所以,他的自由度很大,可以給某一下標無限,跳躍似的賦值
取出所有數組元素
用@符號來代替數組下標
[root@localhost ~]# echo ${A[@]} 5 10 28 bash shell
取得數組個數
${#A[@]}的格式來取得數組的小標
[root@localhost ~]# echo ${#A[@]} 4
如果數組某個下標表示的值為字符串,還可以取得該字符串的長度
${#A[索引]}
如上例中,A【3】的值是bash shell。我們要想知道他的長度可以采用如下
[root@localhost ~]# echo ${#A[3]} 10
刪除數組和刪除變量函數都用的同一個命令。unset
如果要刪除整個數組可以用 unset A
如果要刪除數組中的某個賦值 unset A[3] 就會將bash shell 刪除。我們來試一下
[root@localhost ~]# unset A[3] #將第三個數組值刪除 [root@localhost ~]# echo ${#A[3]} 0 #數組長度變為0 [root@localhost ~]# echo ${A[3]} #值變為空 [root@localhost ~]# echo ${A[@]} 5 10 28 #打印所有變量的時候,也可以證明A[3]確實沒有了 [root@localhost ~]# unset A #取消掉整個數組A [root@localhost ~]# echo ${A[@]} #整個數組A確實取消掉了。沒有數組元素了 [root@localhost ~]#
十 Here Document
bash 有一種特殊的程序區域。就是 Here Document,也可以用來設定變量。
語法為 命令 <<標記
[root@localhost ~]# wc -l << countline > line1 > line2 > line3 > countline 3
Here Document也支持變量替換。在輸入的內容中,如果有變量,bash會在轉向前,將變量值進行替換
[root@localhost ~]# From="From: me@example.edu.cn" #四個變量 [root@localhost ~]# To="To: you@example.edu.cn" [root@localhost ~]# Subject="Subject: Hello world" [root@localhost ~]# Msg="happy new year" [root@localhost ~]# EM="20090310.txt" [root@localhost ~]# cat > $EM <<here #進行轉向 > $From > $To > $Subject > > $Msg > here [root@localhost ~]# cat 20090310.txt From: me@example.edu.cn To: you@example.edu.cn Subject: Hello world happy new year
利用Here Document做多行批注
bash中,只支持單行注釋,#來開頭
利用Here Document來做多行批注,可以用:來操作 : <<DO-NOTHING
第一行,第二行,第三行 DO-NOTHING
利用Here Document夾帶私貨
書中就有一個夾帶私貨的例子。他是用Here Document寫了一個C程序,然后在編譯執行他,以便達到不可告人的目的,看看他是咋寫的
[root@localhost ShellScript]# vim create_prg.sh #! /bin/bash echo "正在產生hello.c。。。。" echo cat <<'EOF' >hello.c #include <stdio.h> int main() { printf("Hello world!\n"); return 0; } EOF echo "編譯hello.c........" echo #編譯Hello.c,並產生執行文件 gcc -o hello hello.c #若編譯成功,則運行 if [ $? -eq 0 ]; then echo "執行 hello....." echo ./hello else echo '執行失敗' fi "create_prg.sh" [新] 27L, 374C 已寫入 [root@localhost ShellScript]# sh create_prg.sh 正在產生hello.c。。。。 編譯hello.c........ 執行 hello..... Hello world! [root@localhost ShellScript]# ls 20090310.txt create_prg.sh hello hello.c
這樣就可以動態編寫c程序,動態執行。神不知鬼不覺。。。