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种不同的反斜杠,应该说明是对第二版本的修订。
版权申明:
转载文章请注明原文出处http://blog.csdn.net/feiyinzilgd/archive/2010/12/30/6108417.aspx
并请联系谭海燕本人或者前往谭海燕个人主页留言