zsh 文件名匹配/替换
我正在尝试创建我的第一个 zsh 完成脚本,在本例中为命令 netcfg。
虽然听起来很蹩脚,但我已经陷入了第一个障碍,免责声明,我知道如何粗略地做到这一点,但是我寻求“ZSH 方式”来做到这一点。
我需要列出 /etc/networking 中的文件,但仅列出文件,而不是目录组件,因此我执行以下操作。
echo $(ls /etc/network.d/*(.))
/etc/network.d/ethernet-dhcp /etc/network.d/wireless-wpa-config
我想要的是:
ethernet-dhcp wireless-wpa-config
所以我尝试(请原谅我的天真):
echo ${(s/*\/)$(ls /etc/network.d/*(.))}
/etc/network.d/ethernet-dhcp /etc/network.d/wireless-wpa-config
看来这不起作用,我确信一定有一些聪明的方法可以通过分成数组并获取最后一部分来做到这一点,但正如我所说,我对此完全是菜鸟。
任何建议都非常感激。
I am trying to create my first zsh completion script, in this case for the command netcfg.
Lame as it may sound I have stuck on the first hurdle, disclaimer, I know how to do this crudely, however I seek the "ZSH WAY" to do this.
I need to list the files in /etc/networking but only the files, not the directory component, so I do the following.
echo $(ls /etc/network.d/*(.))
/etc/network.d/ethernet-dhcp /etc/network.d/wireless-wpa-config
What I wanted was:
ethernet-dhcp wireless-wpa-config
So I try (excuse my naivity) :
echo ${(s/*\/)$(ls /etc/network.d/*(.))}
/etc/network.d/ethernet-dhcp /etc/network.d/wireless-wpa-config
It seems that this doesn't work, I'm sure there must be some clever way of doing this by splitting into an array and getting the last part but as I say, I'm complete noob at this.
Any advice gratefully received.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
一般注意事项:无需使用ls来生成文件名。您不妨使用
echo some*glob
。但如果你想保护可能嵌入的换行符,即使这是一个坏主意。下面的第一个示例直接将全局变量放入数组中以保护嵌入的换行符。第二个使用 printf 生成 NUL 终止数据,以在不使用变量的情况下完成相同的操作。如果您愿意使用变量,这很容易做到:
您也可以在没有变量的情况下做到这一点,但是隔离各个条目的额外内容有点难看:
或者,如果您无论如何都要使用子shell(即前面示例中的命令替换),只需 cd 到该目录,因此它不是 glob 扩展的一部分(另外,您不必重复目录名称):
General note: There is no need to use ls to generate the filenames. You might as well use
echo some*glob
. But if you want to protect the possible embedded newline characters even that is a bad idea. The first example below globs directly into an array to protect embedded newlines. The second one uses printf to generate NUL terminated data to accomplish the same thing without using a variable.It is easy to do if you are willing to use a variable:
You can also do it without a variable, but the extra stuff to isolate individual entries is a bit ugly:
Or, if you are going to use a subshell anyway (i.e. the command substitution in the previous example), just cd to the directory so it is not part of the glob expansion (plus, you do not have to repeat the directory name):
Chris Johnsen 的答案充满了有关 zsh 的有用信息,但是它没有提到在这种特殊情况下有效的更简单的解决方案:
这是使用
t
history 修饰符 作为glob 限定符。Chris Johnsen's answer is full of useful information about zsh, however it doesn't mention the much simpler solution that works in this particular case:
This is using the
t
history modifier as a glob qualifier.感谢你们的建议,伙计们,在阅读了更多 ZSH 并在几天后回到这个问题时,我想我已经有了一个非常简洁的解决方案,为了你们的利益,我想分享一下。
回声 ${$(print /etc/network.d/*(.)):t}
Thanks for your suggestions guys, having done yet more reading of ZSH and coming back to the problem a couple of days later, I think I've got a very terse solution which I would like to share for your benefit.
echo ${$(print /etc/network.d/*(.)):t}
我习惯于看到
basename(1)
剥离目录组件;另外,您可以使用 echo /etc/network/* 来获取文件列表,而无需运行外部 ls 程序。 (运行外部程序可能会比您想要的更慢地完成;我没有找到用于基本名称的 zsh 内置函数,但这并不意味着没有。)我希望以下内容能有所帮助:
I'm used to seeing
basename(1)
stripping off directory components; also, you can useecho /etc/network/*
to get the file listing without running the externalls
program. (Running external programs can slow down completion more than you'd like; I didn't find a zsh-builtin for basename, but that doesn't mean that there isn't one.)Here's something I hope will help: