major=$(awk "//$2= =/"$module/" {print //$1}" /proc/devices)正確理解。
major=$(awk "//$2= =/"$module/" {print //$1}" /proc/devices)
正確理解
導語:
這條語句來自O’REILLY 《LINUX設備驅動第三版》字符設備章節的自動創建設備文件腳本代碼。網上所有的O’REILLY 《LINUX設備驅動第三版》的電子書上一律這條語句。當時這條語句放入腳本,運行怎麼也有錯誤,就錯在雙斜杠的地方。
後來買了一本紙質正版書拜讀,竟然發現書上的代碼以及配套源代碼此處一律用的是單斜杠,就是$的地方隻有一個反斜杠
major=$(awk "/$2==/"$module/" {print /$1}" /proc/devices)
在我的linux上可以正確運行。我使用的是Fedora 9的2.6內核和Red Hat 9的2.4的內核測試的。
初學者剛剛開始讀ldd3的時候,在關於動態創建設備文件的腳本的地方都感覺很困惑。那麼通過我自己實際的操作反複驗證之後得到了針對此語句主要疑難點做出如下解釋:
1.此語句中awk使用了耍號“”,而沒有使用單引號‘’
按照awk的規則和語法,awk整個語句由模式這操作兩部分組成
pattern {action} #如果模式匹配則執行操作
pattern #如果模式匹配則執行打印
{action} #針對每條記錄執行操作
那麼相像的說一條awk語句可以簡化到
A -> B #若A則B
那麼任何腳本,awk也不例外,使用定界符比如:/(awk 正則表達式定界符),“”(字符串定界符)等等,其實最終是讓解析程序認識。
在bash或者是shell腳本中,“”用雙引號引起來的內容中允許變量替換,而用‘’單引號引起來的內容則不允許變量替換包括特殊符號。所以,這樣看開究竟是用單引號還是雙引號來定界內容其實是可以選擇的,沒有說必須是那種方式。
2.此語句中多次使用/反斜杠
目前我們說知道的腳本(bash,shell)都是使用/反斜杠來轉義(SQL中有escape的說法),即是為了保證特殊字符當做普通字符來看。
結合語句和語法來看,對於awk,最終是要接收$1,$2,
我們以一個簡單的例子來看,我們讓一個腳本打印設備misc的設備號。不用這麼複雜的條件模式,用一個簡單的例子來說明這些論述
打印/proc/devices文件中名字為misc的設備號。
[root@localhost feiyinziiu]# cat /proc/devices
Character devices:
1 mem
2 pty
3 ttyp
4 ttyS
5 cua
6 lp
7 vcs
10 misc
13 input
29 fb
36 netlink
128 ptm
129 ptm
130 ptm
131 ptm
這是我的linux下devices的部分文件。按照awk字段來分,這裏1,2,3….應該是$1,而後麵的名字應該是$2。這是我的shell下鍵入命令後的效果
[root@feiyinziiu fbin]# awk "/$2==/"misc/" {print /$1}" /proc/devices
10
[root@feiyinziiu fbin]# awk '$2=="misc" {print $1}' /proc/devices
10
這是正確的結果。試想,如果我們對$不使用反斜杠。
#!/bin/sh
sf=$(awk "$2==/"misc/" {print $1}" /proc/devices)
echo $sf
運行命令:
[root@localhost feiyinziiu]# ./autoawk
awk: cmd. line:1: =="misc" {print }
awk: cmd. line:1: ^ parse error
[root@localhost feiyinziiu]#
這裏報錯。看看這句awk: cmd. line:1: =="misc" {print },為什麼==前是空,print後麵也是空,不應該出現這種情況啊,因為我們明明用的事$2,$1啊,無論怎麼說也不會是空啊。
不著急,我們再對腳本進行修改。
#!/bin/sh
sf=$(awk "$2==/"misc/" {print $0}" /proc/devices)
echo $sf
我們隻將後麵$1改成了$0
運行命令:
[root@localhost feiyinziiu]# ./autoawk
awk: cmd. line:1: =="misc" {print ./autoawk}
awk: cmd. line:1: ^ parse error
awk: cmd. line:1: =="misc" {print ./autoawk}
awk: cmd. line:1: ^ parse error
awk: cmd. line:1: =="misc" {print ./autoawk}
awk: cmd. line:1: ^ unterminated regexp
[root@localhost feiyinziiu]#
現在再來看看報錯情況。
awk: cmd. line:1: =="misc" {print ./autoawk}
print後麵出現了./autoawk
這是我們在bash命令行輸入的。
現在我想你應該想到了,對於bash,shell腳本來說,$0,$1…等等,這些都是命令行輸入參數的引用。
比如:
# ./autoawk a b c d
那麼,$0=./autoawk, $1=a, $2= b, $3 =c。這就開始明白了,如果我們不加反斜杠,那麼$0,$1,$2就會被shell .bash當做它的參數,當腳本運行的時候,$0, $1, $2就會被替換成命令行參數。本來我們是想讓awk接收的,現在卻被shell,bash接收了替換了。為了不讓$1, $2被替換,我們在$前必須加反斜杠來禁止被替換 ,即/$1。禁止這種替換的另一種方法就是用單引號‘’,在腳本中‘’單引號內的內容按原樣處理,不會有任何改變。
單引號和雙引號作用的結果都能打印出相同的結果。唯一的區別是在於雙引號需要對特殊字符轉義,而單引號不需要。
awk "/$2= ="$module" {print /$1}" /proc/devices #這裏$module的引號沒有特殊的用處,因為這裏隻是字符串的引用
awk ‘$2= ="$module" {print $1}’ /proc/devices
這兩種方式達到的效果是一樣的。
3.$前使用了雙反斜杠//$
[root@feiyinziiu fbin]# awk "/$2==/"misc/" {print /$1}" /proc/devices
10
[root@feiyinziiu fbin]# awk '$2=="misc" {print $1}' /proc/devices
10
這裏的演示都是在命令行裏直接鍵入的。shell也好,bash也好,腳本文件最終是讀入到命令解釋器當中的。此地方用反斜杠無非就是保留特殊字符,按照正常情況,/$1就已經達到避免$1被替換的目的了,對於此處//$1,我覺得這是由於版本問題或者是其他原因,而且這種雙斜杠運行時會提示錯誤,所以議這個地方還是以單反斜杠理解。至於到底此處當時為什麼要用雙反斜杠,隻有去問魏永明了。
可以在OREILLY公布的驅動源碼ftp://ftp.ora.com/pub/examples/linux/drivers/中獲得《LINUX設備驅動程序》的源代碼。在我此時寫到這個地方的時候,我又登陸了此服務器,發現裏麵仍然隻有第二版的源碼dd2-samples,還沒有第三版的源碼。ldd2-samples中scull下有個scull_load腳本。裏麵的關於自動創建設備節點的部分代碼如下:
#!/bin/sh
module="scull"
device="scull"
mode="664"
# Group: since distributions do it differently, look for wheel or use staff
if grep '^staff:' /etc/group > /dev/null; then
group="staff"
else
group="wheel"
fi
# invoke insmod with all arguments we got
# and use a pathname, as newer modutils don't look in . by default
/sbin/insmod -f ./$module.o $* || exit 1
major=`cat /proc/devices | awk "//$2= =/"$module/" {print //$1}"`
# Remove stale nodes and replace them, then give gid and perms
# Usually the script is shorter, it's scull that has several devices in it.
rm -f /dev/${device}[0-3]
mknod /dev/${device}0 c $major 0
mknod /dev/${device}1 c $major 1
mknod /dev/${device}2 c $major 2
mknod /dev/${device}3 c $major 3
ln -sf ${device}0 /dev/${device}
chgrp $group /dev/${device}[0-3]
chmod $mode /dev/${device}[0-3]
在我的紙質書同時於此書配套的源代碼都是如下的代碼:
#!/bin/sh # $Id: scull_load,v 1.4 2004/11/03 06:19:49 rubini Exp $ module="scull" device="scull" mode="664" # Group: since distributions do it differently, look for wheel or use staff if grep -q '^staff:' /etc/group; then group="staff" else group="wheel" fi # invoke insmod with all arguments we got # and use a pathname, as insmod doesn't look in . by default /sbin/insmod ./$module.ko $* || exit 1 # retrieve major number major=$(awk "/$2==/"$module/" {print /$1}" /proc/devices) # Remove stale nodes and replace them, then give gid and perms # Usually the script is shorter, it's scull that has several devices in it. rm -f /dev/${device}[0-3] mknod /dev/${device}0 c $major 0 mknod /dev/${device}1 c $major 1 mknod /dev/${device}2 c $major 2 mknod /dev/${device}3 c $major 3 ln -sf ${device}0 /dev/${device} chgrp $group /dev/${device}[0-3] chmod $mode /dev/${device}[0-3] rm -f /dev/${device}pipe[0-3] mknod /dev/${device}pipe0 c $major 4 mknod /dev/${device}pipe1 c $major 5 mknod /dev/${device}pipe2 c $major 6 mknod /dev/${device}pipe3 c $major 7 ln -sf ${device}pipe0 /dev/${device}pipe chgrp $group /dev/${device}pipe[0-3] chmod $mode /dev/${device}pipe[0-3] rm -f /dev/${device}single mknod /dev/${device}single c $major 8 chgrp $group /dev/${device}single chmod $mode /dev/${device}single rm -f /dev/${device}uid mknod /dev/${device}uid c $major 9 chgrp $group /dev/${device}uid chmod $mode /dev/${device}uid rm -f /dev/${device}wuid mknod /dev/${device}wuid c $major 10 chgrp $group /dev/${device}wuid chmod $mode /dev/${device}wuid rm -f /dev/${device}priv mknod /dev/${device}priv c $major 11 chgrp $group /dev/${device}priv chmod $mode /dev/${device}priv
《LINUX設備驅動》官方公布了2種不同的反斜杠,應該說明是對第二版本的修訂。
版權申明:
轉載文章請注明原文出處https://blog.csdn.net/feiyinzilgd/archive/2010/12/30/6108417.aspx
並請聯係譚海燕本人或者前往譚海燕個人主頁留言
最後更新:2017-04-02 04:01:45