shell筆記總結

>>>>>>>
要解決之,可用 hard quote :
$ awk '{print $0}' 1.txt
上面的 hard quote 應好理解,就是將原本的 {、<space>、$(註三)、} 這幾個 shell meta 關閉,
避免掉在 shell 中遭到處理,而完整的成為 awk 參數中的 command meta 。
 
>>>>>>>
若從技術細節來看,shell 會依據 IFS(Internal Field Seperator) 將 command line 所輸入的文字給拆解為"字段"(word)。 
然後再針對特殊字符(meta)先作處理,最後再重組整行 command line 
方法一是使用我們上一章介紹的 ${ } ,也就是用 ${10} 即可。
方法二,就是 shift 了。
用通俗的說法來說,所謂的 shift 就是取消 positional parameter 中最左邊的參數( $0 不受影響)。
其預設值為 1 ,也就是 shift 或 shift 1  都是取消 $1 ,而原本的 $2 則變成 $1、$3 變成 $2 ...
若 shift 3 則是取消前面三個參數,也就是原本的 $4 將變成 $1 ...
那,親愛的讀者,你說要 shift 掉多少個參數,纔可用 $1 取得 ${10} 呢? ^_^
 
>>>>>>>>
$@和$*區別
#/bin/bash
my_fun(){
        echo "$#"
}
echo 'the number of para in "$@" is '$(my_fun "$@" )
echo 'the number of para in $* is '$(my_fun "$*" )
exit 0
 
./my.sh p1 "p2 p3" p4
 
輸出結果
[root@huazi ~]# ./my.sh p1 "p2 p3" p4
the number of para in "$@" is 3
the number of para in $* is 1
 
>>>>>>>
其次,bash 的 test 目前支援的測試對像只有三種:
* string:字串,也就是純文字。
* integer:整數( 0 或正整數,不含負數或小數點)。
* file:文件。
請初學者一定要搞清楚這三者的差異,因為 test 所用的 expression 是不一樣的。
以 A=123 這個變量為例:
* [ "$A" = 123 ]:是字串的測試,以測試 $A 是否為 1、2、3 這三個連續的"文字"。
* [ "$A" -eq 123 ]:是整數的測試,以測試 $A 是否等於"一百二十三"。
* [ -e "$A" ]:是關於文件的測試,以測試 123 這份"文件"是否存在。 
 
>>>>>>>
假如在 test 中碰到變量替換,用 soft quote 是最保險的﹗
* command1 && command2 :其意思是 command2 只有在 RV 為 0 (true) 的條件下執行。
* command1 || command2 :其意思是 command2 只有在 RV 為非 0 (false) 的條件下執行。
$ A=123
$ [ -n "$A" ] && echo "yes! it's ture."
yes! it's ture.
$ unset A
$ [ -n "$A" ] && echo "yes! it's ture."
$ [ -n "$A" ] || echo "no, it's NOT ture."
no, it's NOT ture.
 
>>>>>>>
但,只要你再一次用回單一的 > 來重導的話,那麼,舊的內容還是會被"洗"掉的﹗ 
這時,你要如何避免呢? 
----備份﹗ yes ,我聽到了﹗不過.... 還有更好的嗎? 
既然與施主這麼有緣份,老納就送你一個錦囊妙法吧: 
$ set -o noclobber 
$ echo "4" > file.out 
-bash: file: cannot overwrite existing file
 
那,要如何取消這個"限制"呢? 
哦,將 set -o 換成 set +o 就行: 
$ set +o noclobber 
$ echo "5" > file.out 
$ cat file.out 
 
再問:那... 有辦法不取消而又"臨時"蓋寫目標檔案嗎? 
哦,佛曰:不可告也﹗ 
啊~~~ 開玩笑的、開玩笑的啦~~~ ^_^ 唉,早就料到人心是不足的了﹗ 
$ set -o noclobber 
$ echo "6" >| file.out 
$ cat file.out 
留意到沒有:在 > 後面再加個" | "就好(注意: > 與 | 之間不能有空白哦).... 
 
前面提到:$ cat < file.txt > file.txt 之後原本有內容的檔案結果卻被洗掉了﹗ 
要理解這一現像其實不難,這只是 priority 的問題而已: 
* 在 IO Redirection 中,stdout 與 stderr 的管道會先準備好,才會從 stdin 讀進資料。 
也就是說,在上例中,> file.txt 會先將 file 清空,然後才讀進 < file.txt , 
但這時候檔案已經被清空了,因此就變成讀不進任何資料了... 
 
不過... 然而... 但是... ... stderr 呢? 
好問題﹗不過也容易理解: 
* 若水管漏水怎麼辦? 
也就是說:在 pipe line 之間,前一個命令的 stderr 是不會接進下一命令的 stdin 的, 
其輸出,若不用 2> 導到 file 去的話,它還是送到監視器上面來﹗ 
這點請你在 pipe line 運用上務必要注意的。 
 
或許,你仍意尤未盡﹗或許,你曾經碰到過下面的問題: 
* 在 cm1 | cm2 | cm3 ... 這段 pipe line 中,若要將 cm2 的結果存到某一檔案呢? 
若你寫成 cm1 | cm2 > file | cm3 的話, 
那你肯定會發現 cm3 的 stdin 是空的﹗(當然啦,你都將水管接到別的水池了﹗) 
聰明的你或許會如此解決: 
cm1 | cm2 > file ; cm3 < file
是的,你的確可以這樣做,但最大的壞處是:這樣一來,file I/O 會變雙倍﹗ 
在 command 執行的整個過程中,file I/O 是最常見的最大效能殺手。 
凡是有經驗的 shell 操作者,都會盡量避免或降低 file I/O 的頻率。 
那,上面問題還有更好方法嗎? 
有的,那就是 tee 命令了。 
* 所謂 tee 命令是在不影響原本 I/O 的情況下,將 stdout 複製一份到檔案去。 
因此,上面的命令行可以如此打: 
cm1 | cm2 | tee file | cm3
 
 
>>>>>>>
若你記得  return value ,我想你也應該記得了 && 與 || 是甚麼意思吧?
用這兩個符號再配搭 command group 的話,我們可讓 shell script 變得更加聰明哦。
比方說:
comd1 && {
    comd2
    comd3
    :
} || {
    comd4
    comd5
}
意思是說:
假如 comd1 的 return value 為 true 的話,
然則執行 comd2 與 comd3 ,
否則執行 comd4 與 comd5 。
 
 
事實上,我們在寫 shell script 的時候,經常需要用到這樣那樣的條件以作出不同的處理動作。
用 && 與 || 的確可以達成條件執行的效果,然而,從"人類語言"上來理解,卻不是那麼直觀。
更多時候,我們還是喜歡用 if .... then ... else ... 這樣的 keyword 來表達條件執行。
在 bash shell 中,我們可以如此修改上一段代碼:
if comd1
then
    comd2
    comd3
else
    comd4
    comd5
fi
複製代碼
 
這也是我們在 shell script 中最常用到的 if 判斷式:
只要 if 後面的 command line 返回 true 的 return value (我們最常用 test 命令來送出 return value),
然則就執行 then 後面的命令,否則執行  else 後的命令﹔fi 則是用來結束判斷式的 keyword 。
在 if 判斷式中,else 部份可以不用,但 then 是必需的。
(若 then 後不想跑任何 command ,可用" : " 這個 null command 代替)。
當然,then 或 else 後面,也可以再使用更進一層的條件判斷式,這在 shell script 設計上很常見。
若有多項條件需要"依序"進行判斷的話,那我們則可使用 elif 這樣的 keyword :
if comd1; then
    comd2
elif comd3; then
    comd4
else
    comd5
fi
意思是說:
若 comd1 為 true ,然則執行 comd2 ﹔
否則再測試 comd3 ,然則執行 comd4 ﹔
倘若 comd1 與 comd3 均不成立,那就執行 comd5 。
 
 
if [ "$YN" = Y -o "$YN" = y -o "$YN" = "Yes" -o "$YN" = "yes" -o "$YN" = "YES" ]
if echo "$YN" | grep -q '^[Yy]\([Ee][Ss]\)*$'
 
 
我們常用 case 的判斷式來判斷某一變量在不同的值(通常是 string)時作出不同的處理,
比方說,判斷 script 參數以執行不同的命令。
若你有興趣、且用 Linux 系統的話,不妨挖一挖 /etc/init.d/* 裡那堆 script 中的  case 用法。
如下就是一例:
case "$1" in
  start)
        start
        ;;
  stop)
        stop
        ;;
  status)
        rhstatus
        ;;
  restart|reload)
        restart
        ;;
  condrestart)
        [ -f /var/lock/subsys/syslog ] && restart || :
        ;;
  *)
        echo $"Usage: $0 {start|stop|status|restart|condrestart}"
        exit 1
esac
 
 
>>>>>>>>>
for loop 是從一個清單列表中讀進變量值,並"依次"的循環執行 do 到 done 之間的命令行。
例:
for var in one two three four five
do
    echo -----------
    echo '$var is '$var
    echo
done
上例的執行結果將會是:
1) for 會定義一個叫 var 的變量,其值依次是 one two three four five 。
2) 因為有 5 個變量值,因此 do 與 done 之間的命令行會被循環執行 5 次。
3) 每次循環均用 echo 產生三行句子。
     而第二行中不在 hard quote 之內的 $var 會依次被替換為 one two three four five 。
4) 當最後一個變量值處理完畢,循環結束。
 
倘若 for loop 沒有使用 in 這個 keyword 來指定變量值清單的話,其值將從 $@ (或 $* )中繼承:
for var; do
    ....
done
 
然而,對於一些"累計變化"的項目(如整數加減),for 亦能處理:
for ((i=1;i<=10;i++))
do
   echo "num is $i"
done
 
!!!!!!!!!!!!!!!!!!!!!!!如果不是處理清單,而是處理數值,那麼和while是可以替換的
除了 for loop ,上面的例子我們也可改用  while loop 來做到:
num=1
while [ "$num" -le 10 ]; do
    echo "num is $num"
    num=$(($num + 1))
done
 
* 與 while 相反,until 是在 return value 為 false 時進入循環,否則結束。
因此,前面的例子我們也可以輕鬆的用  until 來寫:
num=1
until [ ! "$num" -le 10 ]; do
    echo "num is $num"
    num=$(($num + 1))
done
複製代碼
 
或是:
num=1
until [ "$num" -gt 10 ]; do
    echo "num is $num"
    num=$(($num + 1))
done
!!!!!!!!!!!!!一直do,直到until那個條件不滿足
 
>>>>>>>>
break 是用來打斷循環,也就是"強迫結束" 循環。
若 break 後面指定一個數值 n 的話,則"從裡向外"打斷第 n 個循環,
預設值為 break 1 ,也就是打斷當前的循環。
在使用 break 時需要注意的是, 它與 return 及 exit 是不同的:
* break 是結束 loop 
* return 是結束 function
* exit 是結束 script/shell
 
>>>>>>>>
cat <<eof >file.txt
>abc
>123
>eof
cat <> file.txt
abc
123
<>表示輸入輸出都是file.txt
 
 
>>>>>>>>
*在列文件或目錄時,有時會遇到“ t”位。“t”代表了粘性位。如果在一個目錄上出現“t”位,這就意味着該目錄中的文件只有其屬主纔可以刪除,即使某個屬組用戶具有和屬主同等的權限。不過有的系統在這一規則上並不十分嚴格。
如果在文件列表時看到“ t”,那麼這就意味着該腳本或程序在執行時會被放在交換區(虛存)。
i權限 也就是不可修改權限  例:chattr u+i aaa 則aaa文件就不可修改,無論任何人,如果刪除就用u-i就好了 
a權限 也就是隻追加權限, 對於日誌系統很好用,這個權限讓目標文件只能追加,不能刪除,而且不能通過編輯器追加。方法和i權限一樣加 
如果想要看某個文件是不是有這個權限,用lsattr filename就行了
 
目錄的權限將會覆蓋該目錄中文件的權限。例如,如果目錄temp具有如下的權限:
drwxr--r--  1   admin            0 10月 19 20:16 temp
而目錄下的文件myfile的權限爲:
-rwxrwxrwx  1   admin           0 10月 19 20:16 myfile
那麼admin組的用戶將無法編輯該文件,因爲它所屬的目錄不具有這樣的權限。
 
chown和chgrp
當你創建一個文件時,你就是該文件的屬主。一旦你擁有某個文件,就可以改變它的所有權,把它的所有權交給另外一個/ e t c / p a s s w d文件中存在的合法用戶。可以使用用戶名或用戶I D號來完成這一操作。
在改變一個文件的所有權時,相應的s u i d也將被清除,這是出於安全性的考慮。只有文件的屬主和系統管理員可以改變文件的所有權。一旦將文件的所有權交給另外一個用戶,就無法再重新收回它的所有權。如果真的需要這樣做,那麼就只有求助於系統管理員了。
 
chown -R -h owner file
- R選項意味着對所有子目錄下的文件也都進行同樣的操作。
- h選項意味着在改變符號鏈接文件的屬主時不影響該鏈接所指向的目標文件。
 
如果你希望知道自己屬於哪些用戶組,可以用ID這個命令:
# su sam
$ id
uid=506(sam) gid=4(adm) groups=4(adm)
# id
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel)
查看當前用戶所屬組
 
# id gem
uid=507(gem) gid=507(group) groups=507(group),0(root),4(adm)
查看其它用戶所用組:#id 用戶名
 
# su sam
$ id gem
uid=507(gem) gid=507(group) groups=507(group),0(root),4(adm)
查看其它用戶所屬組
 
下面的文件,文件屬主是root,文件屬組是admin,root和admin中沒有必然的聯繫,也就是root可以屬於admin組,也可以不屬於admin組
-rwxrw-r-- 1 root admin 34890 10月 19 20:17 httpd.conf
 
 
添加新的用戶賬號使用useradd命令,其語法如下:
useradd 選項 用戶名
    -c comment 指定一段註釋性描述。
  -d 目錄 指定用戶主目錄,如果此目錄不存在,則同時使用-m選項,可以創建主目錄。
  -g 用戶組 指定用戶所屬的用戶組。
  -G 用戶組,用戶組 指定用戶所屬的附加組。
  -s Shell文件 指定用戶的登錄Shell。
  -u 用戶號 指定用戶的用戶號,如果同時有-o選項,則可以重複使用其他用戶的標識號。  
# useradd –d /usr/sam -m sam
此命令創建了一個用戶sam,
其中-d和-m選項用來爲登錄名sam產生一個主目錄/usr/sam(/usr爲默認的用戶主目錄所在的父目錄)。
 
# useradd -s /bin/sh -g group –G adm,root gem
 
修改用戶賬號就是根據實際情況更改用戶的有關屬性,如用戶號、主目錄、用戶組、登錄Shell等。
  修改已有用戶的信息使用usermod命令,其格式如下: 
usermod 選項 用戶名
  常用的選項包括-c, -d, -m, -g, -G, -s, -u以及-o等,這些選項的意義與useradd命令中的選項一樣,可以爲用戶指定新的資源值。另外,有些系統可以使用如下選項  
-l 新用戶名
  這個選項指定一個新的賬號,即將原來的用戶名改爲新的用戶名。
# usermod -s /bin/ksh -d /home/z –g developer sam
  此命令將用戶sam的登錄Shell修改爲ksh,主目錄改爲/home/z,用戶組改爲developer。
 
 
如果是超級用戶,可以用下列形式指定任何用戶的口令:
 
  # passwd sam
  New password:*******
  Re-enter new password:*******
passwd命令還可以用-l(lock)選項鎖定某一用戶,使其不能登錄,例如:  
# passwd -l sam
 
 
groupadd group1
  此命令向系統中增加了一個新組group1,新組的組標識號是在當前已有的最大組標識號的基礎上加1。
groupadd -g 101 group2
  此命令向系統中增加了一個新組group2,同時指定新組的組標識號是101。
# groupmod -g 102 group2
 
# groupmod –g 10000 -n group3 group2
  此命令將組group2的標識號改爲10000,組名修改爲group3。
 
通常用戶標識號的取值範圍是0~65 535。0是超級用戶root的標識號,1~99由系統保留,作爲管理賬號,普通用戶的標識號從100開始。在Linux系統中,這個界限是500。
 
 
>>>>>>>>>>>
添加量用戶批
 
  添加和刪除用戶對每位Linux系統管理員都是輕而易舉的事,比較棘手的是如果要添加幾十個、上百個甚至上千個用戶時,我們不太可能還使用useradd一個一個地添加,必然要找一種簡便的創建大量用戶的方法。Linux系統提供了創建大量用戶的工具,可以讓您立即創建大量用戶,方法如下:
 
  (1)先編輯一個文本用戶文件,每一列按照/etc/passwd密碼文件的格式書寫,要注意每個用戶的用戶名、UID、宿主目錄都不可以相同,其中密碼欄可以留做空白或輸入x號。一個範例文件user.txt內容如下:
 
  user001::600:100:user:/home/user001:/bin/bash
  user002::601:100:user:/home/user002:/bin/bash
  user003::602:100:user:/home/user003:/bin/bash
  user004::603:100:user:/home/user004:/bin/bash
  user005::604:100:user:/home/user005:/bin/bash
  user006::605:100:user:/home/user006:/bin/bash
複製代碼
 
 
  (2)以root身份執行命令/usr/sbin/newusers,從剛創建的用戶文件user.txt中導入數據,創建用戶:
 
  
# newusers < user.txt
複製代碼
 
 
  然後可以執行命令vipw或vi /etc/passwd檢查/etc/passwd文件是否已經出現這些用戶的數據,並且用戶的宿主目錄是否已經創建。
 
  (3)執行命令/usr/sbin/pwunconv,將/etc/shadow產生的shadow密碼解碼,然後回寫到/etc/passwd中,並將/etc/shadow的shadow密碼欄刪掉。這是爲了方便下一步的密碼轉換工作,即先取消shadow password功能。
 
  
# pwunconv
複製代碼
 
 
  (4)編輯每個用戶的密碼對照文件,範例文件passwd.txt內容如下:
 
  user001:密碼
  user002:密碼
  user003:密碼
  user004:密碼
  user005:密碼
  user006:密碼
複製代碼
 
 
  (5)以root身份執行命令/usr/sbin/chpasswd,創建用戶密碼,chpasswd會將經過/usr/bin/passwd命令編碼過的密碼寫入/etc/passwd的密碼欄。
 
  
# chpasswd < passwd.txt
複製代碼
 
 
  (6)確定密碼經編碼寫入/etc/passwd的密碼欄後,執行命令/usr/sbin/pwconv將密碼編碼爲shadow password,並將結果寫入/etc/shadow。
 
  
# pwconv
複製代碼
 
 
  這樣就完成了大量用戶的創建了,之後您可以到/home下檢查這些用戶宿主目錄的權限設置是否都正確,並登錄驗證用戶密碼是否正確。
 
 
 
 
>>>>>>>>>>>
 我們不可以使用su讓他們直接變成root,因爲這些用戶都必須知道root的密碼,這種方法很不安全,而且也不符合我們的分工需求。一般的做法是利用權限的設置,依工作性質分類,讓特殊身份的用戶成爲同一個工作組,並設置工作組權限。例如:要wwwadm這位用戶負責管理網站數據,一般Apache Web Server的進程httpd的所有者是www,您可以設置用戶wwwadm與www爲同一工作組,並設置Apache默認存放網頁目錄/usr/local/httpd/htdocs的工作組權限爲可讀、可寫、可執行,這樣屬於此工作組的每位用戶就可以進行網頁的管理了。
 
注意:配置文件/etc/sudoers必須使用命令 Visudo來編輯。
 
  只要把相應的用戶名、主機名和許可的命令列表以標準的格式加入到文件/etc/sudoers,並保存就可以生效,再看一個例子。
 
 
 
>>>>>>>>>>>>>>
F i n d命令的一般形式爲:
 
find pathname -options [-print -exec -ok]
 
 
pathname:  find命令所查找的目錄路徑。例如用.來表示當前目錄,用/來表示系統根目錄。
-print:     find命令將匹配的文件輸出到標準輸出。
-exec:     find命令對匹配的文件執行該參數所給出的s h e l l命令。相應命令的形式爲' command' {} \;,注意{ }和\;之間的空格。
!!!!!!!!!!!!!!!!!!!!可以理解爲分號是-exec的參數之一,不能被當前shell解釋執行,因此需要轉換符
-ok:       和- e x e c的作用相同,只不過以一種更爲安全的模式來執行該參數所給出的s h e l l命令,在執行每一個命令之前,都會給出提示,讓用戶來確定是否執
 
 
# find . -type f -exec ls -l {} \;
-rw-r--r--    1 root     root        34928 2003-02-25  ./conf/httpd.conf
-rw-r--r--    1 root     root        12959 2003-02-25  ./conf/magic
-rw-r--r--    1 root     root          180 2003-02-25  ./conf.d/README
 
$ find . -name "*.conf"  -mtime +5 -ok rm {} \;
< rm ... ./conf/httpd.conf > ? n
$ find logs -type f -mtime +5 -exec rm {} \;
 
$ find $HOME -print
$ find ~ -print
 
$ find . -type f -perm 644 -exec ls -l {} \;
$ find / -type f -size 0 -exec ls -l {} \;
查找/var/logs目錄中更改時間在7日以前的普通文件,並在刪除之前詢問它們:
$ find /var/logs -type f -mtime +7 -ok rm {} \;
 
 
爲了查找系統中所有的r m t磁帶設備,可以用:
$ find /dev/rmt -print
 
>>>>>>>>>>>>>>>>>
在使用f i n d命令的- e x e c選項處理匹配到的文件時, f i n d命令將所有匹配到的文件一起傳遞給e x e c執行。但有些系統對能夠傳遞給e x e c的命令長度有限制,這樣在f i n d命令運行幾分鐘之後,就會出現溢出錯誤。錯誤信息通常是“參數列太長”或“參數列溢出”。這就是x a rg s命令的用處所在,特別是與f i n d命令一起使用。
 
 F i n d命令把匹配到的文件傳遞給x a rg s命令,而x a rg s命令每次只獲取一部分文件而不是全部,不像- e x e c選項那樣。這樣它可以先處理最先獲取的一部分文件,然後是下一批,並如此繼續下去。
 
      在有些系統中,使用- e x e c選項會爲處理每一個匹配到的文件而發起一個相應的進程,並非將匹配到的文件全部作爲參數一次執行;這樣在有些情況下就會出現進程過多,系統性能下降的問題,因而效率不高;
       而使用x a rg s命令則只有一個進程。另外,在使用x a rg s命令時,究竟是一次獲取所有的參數,還是分批取得參數,以及每一次獲取參數的數目都會根據該命令的選項及系統內核中相應的可調參數來確定。
 
 
 
#find . -type f -print | xargs file
./.kde/Autostart/Autorun.desktop: UTF-8 Unicode English text
./.kde/Autostart/.directory:      ISO-8859 text\
 
 
在整個系統中查找內存信息轉儲文件(core dump) ,然後把結果保存到/tmp/core.log 文件中:
$ find / -name "core" -print | xargs echo  >/tmp/core.log
 
 
# find . -perm -7 -print | xargs chmod o-w
# ls -l
drwxrwxr-x    2 sam      adm          4096 10月 30 20:14 file6
-rwxrwxr-x    2 sam      adm             0 10月 31 01:01 http3.conf
-rwxrwxr-x    2 sam      adm             0 10月 31 01:01 httpd.conf
 
 
用g r e p命令在所有的普通文件中搜索hostname這個詞:
# find . -type f -print | xargs grep "hostname"
./httpd1.conf:#     different IP addresses or hostnames and have them handled by the
./httpd1.conf:# VirtualHost: If you want to maintain multiple domains/hostnames
on your
 
 
 
想要的當前目錄及子目錄中查找文件名以一個大寫字母開頭的文件,可以用:
$ find . -name "[A-Z]*" -print
複製代碼
 
 
想要在/ e t c目錄中查找文件名以h o s t開頭的文件,可以用:
$ find /etc -name "host*" -print
複製代碼
 
 
想要查找$ H O M E目錄中的文件,可以用:
$ find ~ -name "*" -print 或find . -print
複製代碼
 
 
要想讓系統高負荷運行,就從根目錄開始查找所有的文件。
$ find / -name "*" -print
 
如果想在當前目錄查找文件名以兩個小寫字母開頭,跟着是兩個數字,最後是* . t x t的文件,下面的命令就能夠返回名爲a x 3 7 . t x t的文件:$
$find . -name "[a-z][a-z][0--9][0--9].txt" -print
 
 
比如要在/usr/sam目錄下查找不在dir1子目錄之內的所有文件 
find /usr/sam -path "/usr/sam/dir1" -prune -o -print  
find [path ..] [expression] 在路徑列表的後面的是表達式 
-path "/usr/sam" -prune -o -print 是 -path "/usr/sam" -a -prune -o -print 的簡寫表達式按順序求值, -a 和 -o 都是短路求值,與 shell 的 && 和 || 類似如果 -path "/usr/sam" 爲真,則求值 -prune , -prune 返回真,與邏輯表達式爲真;否則不求值 -prune ,與邏輯表達式爲假。 如果 -path "/usr/sam" -a -prune 爲假,則求值 -print ,-print 返回真,或邏輯表達式爲真;否則不求值 -print,或邏輯表達式爲真。
避開多個文件夾 
find /usr/sam \( -path /usr/sam/dir1 -o -path /usr/sam/file1 \) -prune -o -print
圓括號表示表達式的結合。 
\ 表示引用,即指示 shell 不對後面的字符作特殊解釋,而留給 find 命令去解釋其意義。
 
按文件屬主查找文件,如在$ H O M E目錄中查找文件屬主爲sam的文件,可以用:
$ find ~ -user sam -print
 
爲了查找屬主帳戶已經被刪除的文件,可以使用- n o u s e r選項。這樣就能夠找到那些屬主在/ e t c / p a s s w d文件中沒有有效帳戶的文件。在使用- n o u s e r選項時,不必給出用戶名; f i n d命令能夠爲你完成相應的工作。
例如,希望在/ h o m e目錄下查找所有的這類文件,可以用:
$ find /home -nouser -print
就像u s e r和n o u s e r選項一樣,針對文件所屬於的用戶組, f i n d命令也具有同樣的選項,爲了在/ a p p s目錄下查找屬於gem用戶組的文件,可以用:
$ find /apps -group gem -print
查找沒有有效所屬用戶組的所有文件,可以使用n o g r o u p選項。下面的f i n d命令從文件系統的根目錄處查找這樣的文件
$ find / -nogroup-print
 
 
查找更改時間比文件sam新但比文件temp舊的文件:
# find -newer httpd1.conf  ! -newer temp -ls
1077669    0 -rwxrwxr-x   2 sam      adm             0 10月 31 01:01 ./httpd.conf
1077671    4 -rw-rw-rw-   1 root     root         2792 10月 31 20:19 ./temp
1077673    0 -rw-r--r--   1 sam      adm             0 10月 31 01:07 ./fiel
 
在當前目錄下查找文件長度大於1 M字節的文件:
$ find . -size +1000000c -print
在/ h o m e / a p a c h e目錄下查找文件長度恰好爲1 0 0字節的文件:
$ find /home/apache -size 100c -print
 
 
在使用f i n d命令時,可能希望先匹配所有的文件,再在子目錄中查找。使用d e p t h選項就可以使f i n d命令這樣做。這樣做的一個原因就是,當在使用f i n d命令向磁帶上備份文件系統時,希望首先備份所有的文件,其次再備份子目錄中的文件。
在下面的例子中, f i n d命令從文件系統的根目錄開始,查找一個名爲C O N . F I L E的文件。
它將首先匹配所有的文件然後再進入子目錄中查找。
$ find / -name "CON.FILE" -depth -print
 
 
在當前的文件系統中查找文件(不進入其他文件系統),可以使用f i n d命令的m o u n t選項。
從當前目錄開始查找位於本文件系統中文件名以X C結尾的文件:
$ find . -name "*.XC" -mount -print
 
>>>>>>>>>>>>>>>
下面就是這些域:
第1列分鐘1~5 9
第2列小時1~2 3(0表示子夜)
第3列日1~3 1
第4列月1~1 2
第5列星期0~6(0表示星期天)
第6列要運行的命令
 
系統管理員是通過c r o n . d e n y和c r o n . a l l o w這兩個文件來禁止或允許用戶擁有自己的c r o n t a b文件。
 
10 1 * * 6,0 /bin/find -name "core" -exec rm {} \;
上面的例子表示每週六、週日的1 : 1 0運行一個f i n d命令。
 
 
!!!!!!!!!!!!確信前面5個域用空格分隔。
提交你剛剛創建的c r o n t a b文件,可以把這個新創建的文件作爲c r o n命令的參數:
$su sam
crontab samcron
 
恢復丟失的crontab文件
如果不小心誤刪了c r o n t a b文件,假設你在自己的$ H O M E目錄下還有一個備份,那麼可以將其拷貝到/ v a r / s p o o l / c r o n / < u s e r n a m e >,其中< u s e r n a m e >是用戶名。如果由於權限問題無法完成拷貝,可以用:
$ crontab <filename>
 
以在a t命令後面跟上日期/時間並回車。然後就進入了a t命令提示符,這時只需逐條輸入相應的命令,然後按‘ < C T R L - D >’退出。
# su sam
$ at 10:40
warning: commands will be executed using (in order) a) $SHELL b) login shell c) /bin/sh
at> find /etc -name "passwd" -print
at> <EOT>
job 1 at 2004-11-02 10:40
 
 
如果希望向a t命令提交一個s h e l l腳本,使用其命令行方式即可。在提交腳本時使用- f選項。
如:
$ touch db_table.sh
$ at 3:00pm tomorrow -f db_table.sh
warning: commands will be executed using (in order) a) $SHELL b) login shell c) /bin/sh
job 3 at 2004-11-02 15:00
 
清除作業的命令格式爲:
atrm [job no] 或at -r [job no]
 
要清除某個作業,首先要執行at -l命令,以獲取相應的作業標識,然後對該作業標識使用at -r 命令,清除該作業。
$ at -l
1       2004-11-02 10:40 a sam
3       2004-11-02 15:00 a sam
4       2004-11-01 19:07 a sam
$at -r 3
$at -l
1       2004-11-02 10:40 a sam
4       2004-11-01 19:07 a sam
 
 
>>>>>>>>>>>>>>>>>
2)列出log.開頭、後面跟隨一個數字、然後可以是任意字符串的文件名:
#ls log.[0-9]*
3)與例二相反,列出log.開頭、後面不跟隨一個數字、然後可以是任意字符串的文件名
#ls log.[!0-9]*
 
爲了列出所有以數字開頭的文件名:
$ ls [0-9]*
列出所有以. 開頭的文件名(隱含文件,例如. p r o f i l e、. r h o s t s、. h i s t o r y等):
$ ls .*
 
在LINUX中,要使轉義符生效,需加參數-e
# echo -e "\007your home is $HOME , you are connected on `tty`"
your home is /root , you are connected on /dev/pts/1
# echo -e "\ayour home is $HOME , you are connected on `tty`"
your home is /root , you are connected on /dev/pts/1
 
把 httpd.conf 的內容加上行號後輸入 httpd1.conf 這個文件裏
$cat -n httpd.conf > httpd1.conf
 
-n 或 --number 由 1 開始對所有輸出的行數編號 
-b 或 --number-nonblank 和 -n 相似,只不過對於空白行不編號 
 
列出文本文件slayers.story的內容,同時複製3份副本,文件名稱分別爲ss-copy1、ss-copy2、ss-copy3: 
$ cat slayers.story |tee ss-copy1 ss-copy2 ss-copy3
 
>>>>>>>>>>>>>>>>>
e x e c命令可以用來替代當前s h e l l;換句話說,並沒有啓動子s h e l l。使用這一命令時任何現有環境都將會被清除,並重新啓動一個s h e l l。它的一般形式爲:
exec command
其中的c o m m a n d通常是一個s h e l l腳本。
 
要解決之,可用 hard quote : 
$ awk '{print $0}' 1.txt
要是理解了 hard quote 的功能,再來理解 soft quote 與 escape 就不難: 
awk "{print \$0}" 1.txt 
awk \{print\ \$0\} 1.txt
 
比方說:已有變量 $A 的值是 0 ,那如何在 command line 中解決 awk 的 $$A 呢? 那麼 hard quoe 就不可行了: 
代碼: 
$ awk '{print $$A}' 1.txt
因爲 $A 的 $ 在 hard quote 中是不能替換變量的。 
可以使用如下幾種方案:
A=0 
awk "{print \$$A}" 1.txt 
awk \{print\ \$$A\} 1.txt 
awk '{print $'$A'}' 1.txt 
awk '{print $'"$A"'}' 1.txt     # 注:"$A" 包在 soft quote 中
 
>>>>>>>>>>>>>>>>>>>>>>>>>>
有三種方式調用a w k,第一種是命令行方式
第二種方法是將所有a w k命令插入一個文件,並使a w k程序可執行,然後用a w k命令解釋器作爲腳本的首行,以便通過鍵入腳本名稱來調用它
第三種方式是將所有的a w k命令插入一個單獨文件,然後調用:
awk -f awk-script-file input-files(s)
- f選項指明在文件a w k _ s c r i p t _ f i l e中的a w k腳本, i n p u t _ f i l e ( s )是使用a w k進行瀏覽的文件名
 
實際上任何腳本都是從標準輸入中接受輸入的。爲運行本章腳本,使用a w k腳本輸入文件格式,例如:
belts.awk grade_student.txt
也可替代使用下述格式:
使用重定向方法:
belts.awk < grade2.txt
或管道方法:
grade2.txt | belts.awk
 
當第一次使用a w k時,可能被錯誤信息攪得不知所措,但通過長時間和不斷的學習,可總結出以下規則。在碰到a w k錯誤時,可相應查找:
" 確保整個a w k命令用單引號括起來。
" 確保命令內所有引號成對出現。
" 確保用花括號括起動作語句,用圓括號括起條件語句。
" 可能忘記使用花括號,也許你認爲沒有必要,但a w k不這樣認爲,將按之解釋語法
 
$1=="huazi"精確匹配
$1~/huazi/ 簡單匹配
爲抽取級別爲y e l l o w或b r o w n的記錄,使用豎線符|。意爲匹配| 兩邊模式之一。注意,使用豎線符時,語句必須用圓括號括起來。
[root@Linux_chenwy sam]# awk '$0 ~/(Yellow|Brown)/' grade.txt
 
A R G C支持命令行中傳入a w k腳本的參數個數。A R G V是A R G C的參數排列數組,其中每一元素表示爲A R G V [ n ],n爲期望訪問的命令行參數。
E N V I R O N 支持系統設置的環境變量,要訪問單獨變量,使用實際變量名,例如E N V I R O N [“E D I TO R”] =“Vi”。
F I L E N A M E支持a w k腳本實際操作的輸入文件。因爲a w k可以同時處理許多文件,因此如果訪問了這個變量,將告之系統目前正在瀏覽的實際文件。
F N R支持a w k目前操作的記錄數。其變量值小於等於N R。如果腳本正在訪問許多文件,每一新輸入文件都將重新設置此變量。
F S用來在a w k中設置域分隔符,與命令行中- F選項功能相同。缺省情況下爲空格。如果用逗號來作域分隔符,設置F S = ","。
N F支持記錄域個數,在記錄被讀之後再設置。
O F S允許指定輸出域分隔符,缺省爲空格。如果想設置爲#,寫入O F S = " # "。
O R S爲輸出記錄分隔符,缺省爲新行( \ n)。
R S是記錄分隔符,缺省爲新行( \ n )。
 
!!!!!!!!!!!!!!!!!!!!!
awk 'gsub("ftp","http"){print $0}' /etc/passwd
可以這樣理解:花掛號前是真,則print
awk '{if(gsub("ftp","http"))print $0}' /etc/passwd 
效果一樣
 
 
在查看a w k腳本前,先來查看怎樣在a w k命令行中傳遞變量。
在a w k執行前將值傳入a w k變量,需要將變量放在命令行中,格式如下:
awk 命令變量=輸入文件值
複製代碼
 
(後面會講到怎樣傳遞變量到a w k腳本中)。
下面的例子在命令行中設置變量A G E等於1 0,然後傳入a w k中,查詢年齡在1 0歲以下的所有學生。
[root@chenwy sam]# awk '{if ($5<AGE) print $0}' AGE=10 grade.txt
M.Tans 5/99 48311 Green 8 40 44
J.Lulu 06/99 48317 green 9 24 26
 
 
 awk腳本文件
可以將a w k腳本寫入一個文件再執行它。命令不必很長(儘管這是寫入一個腳本文件的主要原因),甚至可以接受一行命令。這樣可以保存a w k命令,以使不必每次使用時都需要重新輸入。使用文件的另一個好處是可以增加註釋,以便於理解腳本的真正用途和功能。
使用前面的幾個例子,將之轉換成a w k可執行文件。像原來做的一樣,將學生目前級別分相加awk ‘(t o t + = $ 6) END{print "club student total points:" t o t }’ g r a d e . t x t。
創建新文件s t u d e n t _ t o t . a w k,給所有a w k程序加入a w k擴展名是一種好習慣,這樣通過查看文件名就知道這是一個a w k程序。文本如下:
 
[sam@chenwy sam]$ cat student_tot.awk
#!/bin/awk -f
#all commnet lines must start with a hash '#'
#name:students_tots.awk
#to call:student_tot.awk grade.txt
#prints total and average of club student points
 
#print a header first
BEGIN{
print "Student  Date  Member  No.  Grade Age  Points Max"
print "Name     Joined                        Gained  Point Available"
print "=============================================================="
}
#let's add the scores of points gained
(tot+=$6)
 
#finished proessing now let's print the total and average point
END{
print "Club student total points :" tot
print "Average Club Student Points:" tot/NR}
 
 
使用a w k腳本時,記住設置F S變量是在B E G I N部分。如果不這樣做, a w k將會發生混淆,不知道域分隔符是什麼。
[sam@Linux_chenwy sam]$ cat passwd.awk
#!/bin/awk -f
#to call:passwd.awk /etc/passwd
#print out the first and seventh fields
BEGIN{
FS=":"}
{print $1,"\t",$7}
 
[sam@Linux_chenwy sam]$ cat fieldcheck.awk
#!/bin/awk -f
#check on how many fields in a file
#name:fieldcheck.awk
#to call:fieldcheck MAX=n FS=<separator> filename
#
NF!=MAX{
print("line" NR " does not have " MAX "fields")}
複製代碼
 
如果NF中的值不等於最大MAX值,則打印出"哪一行的域總數不是max"
 
如果以/ e t c / p a s s w d作輸入文件(p a s s w d文件有7個域),運行上述腳本。參數格式如下:
[sam@Linux_chenwy sam]$ chmod u+x fieldcheck.awk
[sam@Linux_chenwy sam]$ ./fieldcheck.awk MAX=7 FS=":" passwd
 
>>>>>>>>>>>>>>>>>>
調用s e d有三種方式:在命令行鍵入命令;將s e d命令插入腳本文件,然後調用s e d;將s e d命令插入腳本文件,並使s e d腳本可執行。
s e d選項如下:
n 不打印;s e d不寫編輯行到標準輸出,缺省爲打印所有行(編輯和未編輯)。p命令可以用來打印編輯行。
c 下一命令是編輯命令。使用多項編輯時加入此選項。如果只用到一條s e d命令,此選項無用,但指定它也沒有關係。
f 如果正在調用s e d腳本文件,使用此選項。此選項通知s e d一個腳本文件支持所有的s e d命令,例如:sed -f myscript.sed input_file,這裏m y s c r i p t . s e d即爲支持s e d命令的文件。
 
插入新行
[sam@chenwy sam]$ sed "/company/a\Then suddenly it happened." quote.txt
The honeysuckle band played all night long for only $90.
It was an evening of splendid music and company.
Then suddenly it happened.
Too bad the disco floor fell through at 23:00.
The local nurse Miss P.Neave was in attendance.
插入命令類似於附加命令,只是在指定行前面插入。和附加命令一樣,它也只接受一個地址。
如在a t t e n d a n c e結尾的行前插入文本utter confusion followed。
[sam@chenwy sam]$ sed "/company/i\Utter confusion followed." quote.txt
 
可以對同一個腳本中的相同文件進行修改、附加、插入三種動作匹配和混合操作。
[sam@chenwy sam]$ cat mix.sed
#!/bin/sed -f
1 c\
The Dibble band were grooving.
 
/evening/ i\
They played some great tunes.
 
3 a\
Where was the nurse to help?
 
[sam@chenwy sam]$ sed "/honeysuck/c\The Office Dibble band played well." quote.txt
The Office Dibble band played well.
It was an evening of splendid music and company.
Too bad the disco floor fell through at 23:00.
The local nurse Miss P.Neave was in attendance.
 
刪除第一行;1 d意爲刪除第一行。
[sam@chenwy sam]$ sed '1d' quote.txt
It was an evening of splendid music and company.
Too bad the disco floor fell through at 23:00.
The local nurse Miss P.Neave was in attendance.
複製代碼
 
 
刪除第一到第三行:
[sam@chenwy sam]$ sed '1,3d' quote.txt
The local nurse Miss P.Neave was in attendance.
 
g 缺省情況下只替換第一次出現模式,使用g選項替換全局所有出現模式。
p 缺省s e d將所有被替換行寫入標準輸出,加p選項將使- n選項無效。- n選項不打印輸出結果。
w 文件名使用此選項將輸出定向到一個文件。
[sam@chenwy sam]$ sed 's/night/NIGHT/' quote.txt
The honeysuckle band played all NIGHT long for only $90.
It was an evening of splendid music and company.
Too bad the disco floor fell through at 23:00.
The local nurse Miss P.Neave was in attendance.
 
要從$ 9 0 中刪除$ 符號(記住這是一個特殊符號,必須用\ 屏蔽其特殊含義),在r e p l a c e m e n t - p a t t e r n部分不寫任何東西,保留空白,但仍需要用斜線括起來。在s e d中也可以這樣刪除一個字符串。
[sam@chenwy sam]$ sed 's/\$//' quote.txt
The honeysuckle band played all night long for only 90.
It was an evening of splendid music and company.
Too bad the disco floor fell through at 23:00.
The local nurse Miss P.Neave was in attendance.
 
將替換結果寫入一個文件用w選項,下面的例子將s p l e n d i d替換爲S P L E N D I D的替換結果寫入文件s e d . o u t:
[sam@chenwy sam]$ sed 's/splendid/SPLENDID/w sed.out' quote.txt 
The honeysuckle band played all night long for only $90.
It was an evening of SPLENDID music and company.
Too bad the disco floor fell through at 23:00.
The local nurse Miss P.Neave was in attendance.
 
任務是在每一行末尾加一個字符串‘ p a s s e d’。
使用$命令修改各域會使工作相對容易些。首先需要匹配至少兩個或更多的數字重複出現,這樣將所有的帳號加進匹配模式。
[sam@chenwy sam]$ sed 's/[0-9][0-9]*/& Passed/g' ok.txt
AC456 Passed
AC492169 Passed
AC9967 Passed
AC88345 Passed
 
>>>>>>>>>>>>>>>>>>
大寫到小寫
除了刪除控制字符,轉換大小寫是t r最常用的功能。爲此需指定即將轉換的小寫字符[ a - z ]和轉換結果[ A - Z ]。
第一個例子,t r從一個包含大小寫字母的字符串中接受輸入。
[sam@chenwy split]$ echo "May Day,May Day,Going Down.." | tr "[a-z]" "[A-Z]"
MAY DAY,MAY DAY,GOING DOWN..
複製代碼
 
 
同樣,也可以使用字符類[:l o w e r:]和[:u p p e r:]。
[sam@chenwy split]$ echo "May Day,May Day,Going Down.." | tr "[:lower:]" "[:upper:]"
MAY DAY,MAY DAY,GOING DOWN..
 
>>>>>>>>>>>
再談談登錄shell和非登錄shell
登錄shell指的是當用戶登錄linux系統時,所取得的那個shell,當登錄以後,再去執行其他的shell,其他的shell就是非登錄shell了。
最常見的一種情況就是在X Window下,啓動終端,那些shell都是非登錄shell
還有一種情況是以一個用戶登錄有,使用命令bash切換到一個新的環境,這個也是非登錄shell了。
把握好登錄這兩個字就可以了。
還有它們讀取文件的區別。
登錄shell會讀取~/.bash_profile和~/.bashrc兩個文件
非登錄shell僅僅是讀取~/.bashrc文件
 
s t t y用於設置終端特性。要查詢現在的s t t y選項,使用stty -a。
$ stty -a
speed 38400 baud; rows 24; columns 80; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = M-^?; eol2 = M-^?;
swtch = M-^?; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W;
lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 hupcl -cstopb cread -clocal -crtscts
-ignbrk brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff
-iuclc ixany imaxbel iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
echoctl echoke
複製代碼
上面中^C表示Ctrl+C的意思。其他的依次類推。下面列舉幾個參數代表的含義。更多的請參考man stty
eof:End Of File 文件結束的意思
erase: 向後刪除字符
kill: 刪除在當前命令行上的所有文字
quit: 給當前正在執行的進程發送一個quit信號
stop: 停止當前屏幕的輸出
這些設置值,和我們日常用的Ctrl+D,ctrl+U等操作相關。一般情況下沒有必要改動。
假如想要用ctrl+H進行字符從刪除,可以這麼設置
# stty erase ^H
 
數值測試
可以用e x p r測試一個數。如果試圖計算非整數,將返回錯誤。
[root@localhost ~]# expr rr + 1
expr: non-numeric argument
 
e x p r命令一般用於整數值,但也可用於字符串。
 
[root@localhost ~]# VALUE=hello
[root@localhost ~]# expr $VALUE = "hello"
1
[root@localhost ~]# echo $?
0
 
>>>>>>>>>>
不必拘泥於變量或數值測試,也可以測知系統命令是否成功返回。對g r e p使用i f語句找出
g r e p是否成功返回信息。下面的例子中g r e p用於查看D a v e是否在數據文件d a t a . f i l e中,注意
‘D a v e \ >’用於精確匹配。
[root@localhost ~]# cat grepif.sh 
#!/bin/sh
# grepif.sh
if grep 'Dave\>' data.file > /dev/null 2>&1
then
                echo "Great Dave is in the file"
else
                echo "No Dave is not in the file"
fi
 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章