>>>>>>>
要解決之,可用 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