LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1485|回复: 13

求一个匹配 shell 通配符的函数

[复制链接]
发表于 2008-1-7 12:28:45 | 显示全部楼层 |阅读模式
Vim 开发时遇到的一个问题,需要一个可以展开 shell 通配符的函数。

描述:
用 POSIX shell(或一系列 POSIX 工具)写一个函数来模拟 csh 的 glob (或 zsh 的
print -N)

简单解释:
例如,csh 的 'glob *.txt' 和 zsh 的 'print -N *.txt' 都可以返回以NULL为分割符的当前目录里的 txt 文件名列表。

几点要求:
1) 可移植性,所有 POSIX 兼容 shell.
2) 性能
3) 代码尽可能简洁


为了说清楚,再举两个例子。
例1: (返回 /usr/ 下的文件及目录名称列表)
$ for i in /usr/*; do printf "%s\0" $i; done

例2: (返回当前目录下的扩展名为o 的文件列表)
$ printf "%s\0" *.o

例1 和 例2 就是需要的功能, 但是都有各自的问题。

例1 的问题是性能。当可匹配的数目巨大时,性能差。
例2 的问题是, 如果 printf 不是built-in 的 (像ksh),则参数的数目受限(当匹配数
目接近ARG_MAX 时, 会有 "Argument list too long", 的错误。)

我考虑过用 find, awk 等工具代替,可是个人能力有限,对 shell 不太熟
悉,不知大家有没有好的解决办法?谢谢!
发表于 2008-1-7 12:59:45 | 显示全部楼层
这样行不行

  1. find . -maxdepth 1 -print0 # . 目录会包含在结果中
  2. find . -maxdepth 1 -mindepth 1 -print0 # . 目录不包含在结果中
复制代码

这两种方法的问题都是它们打印出的结果是带路径的, 比如 aa 显示为 ./aa
回复 支持 反对

使用道具 举报

发表于 2008-1-7 15:06:31 | 显示全部楼层
例2改为这样呢?
ls | xargs -n1 printf "%s\0"
回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-1-7 20:39:15 | 显示全部楼层
Post by remote fish;1803963
这样行不行

  1. find . -maxdepth 1 -print0 # . 目录会包含在结果中
  2. find . -maxdepth 1 -mindepth 1 -print0 # . 目录不包含在结果中
复制代码

这两种方法的问题都是它们打印出的结果是带路径的, 比如 aa 显示为 ./aa


输出是一个问题,还有一个问题就是find -name 的 pattern 是不是与shell完全一致。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-1-7 20:46:08 | 显示全部楼层
Post by ly5066113;1804015
例2改为这样呢?
ls | xargs -n1 printf "%s\0"


可能是我没说明白(我修改了一下原贴的说明),例子中的 '*' 可以是一个 pattern。 例如可能是:*.txt。

所以这个若写为:
ls * | xargs -n1 printf "%s\0"
才符合要求,但是同样存在参数限制和效率问题。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-1-7 21:03:11 | 显示全部楼层
为了简化问题,我这样描述:请改进下面这个函数的效率,或重写一个与之功能相同的函数。

[PHP]
vimglob () {
      while [ $# -ge 1 ];
       do
               exec printf "%s\0" $1
               shift
       done
}
[/PHP]

$ vimglob *.txt
回复 支持 反对

使用道具 举报

发表于 2008-1-7 21:04:55 | 显示全部楼层
Post by Dasn;1804158
可能是我没说明白(我修改了一下原贴的说明),例子中的 '*' 可以是一个 pattern。 例如可能是:*.txt。

所以这个若写为:
ls * | xargs -n1 printf "%s\0"
才符合要求,但是同样存在参数限制和效率问题。


ls * | xargs -n1 printf "%s\0"
这样写,是不会存在参数限制的问题的,xagrs -n1每次只会传一个参数给printf,xargs是专门解决Argument list too long的问题的。至于效率问题,我没有测试过,不太清楚。
如果你觉得awk会高一些,那么可以试试:
ls * | awk '{printf "%s\0" ,$0}'
回复 支持 反对

使用道具 举报

发表于 2008-1-7 21:13:11 | 显示全部楼层
awk的效率真的会高一些:
$ time ls * | awk '{printf "%s\0" ,$0}'
real    0m0.01s
user    0m0.00s
sys     0m0.01s
$ time ls * | xargs -n1 printf "%s\0"
real    0m0.18s
user    0m0.04s
sys     0m0.13s
回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-1-7 21:17:29 | 显示全部楼层
Post by ly5066113;1804169
ls * | xargs -n1 printf "%s\0"
这样写,是不会存在参数限制的问题的,xagrs -n1每次只会传一个参数给printf,xargs是专门解决Argument list too long的问题的。至于效率问题,我没有测试过,不太清楚。
如果你觉得awk会高一些,那么可以试试:
ls * | awk '{printf "%s\0" ,$0}'


我想应该是 ls 的 Argument list too long 。
回复 支持 反对

使用道具 举报

发表于 2008-1-7 22:00:17 | 显示全部楼层
Post by Dasn;1804181
我想应该是 ls 的 Argument list too long 。


那这样好了,ls的时候不写参数,判断交给awk:
ls | awk '/*\.txt/{printf "%s\0" ,$0}'
这样参数和性能的问题就都能解决了。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表