zsh文件名为globbling / substitution

时间:2010-07-05 09:26:22

标签: autocomplete zsh glob

我正在尝试创建我的第一个zsh完成脚本,在本例中为命令netcfg。

Lame听起来可能听起来我已经陷入了第一道障碍,免责声明,我知道如何粗暴地做到这一点,但我寻求“ZSH WAY”来做到这一点。

我需要列出/ 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

似乎这不起作用,我敢肯定必须有一些聪明的方法来做到这一点,分成一个数组并得到最后一部分,但正如我所说,我完全没有这个。

感谢任何建议。

4 个答案:

答案 0 :(得分:7)

一般说明:无需使用 ls 生成文件名。您也可以使用echo some*glob。但是如果你想保护可能的嵌入式换行符,即使这是一个坏主意。下面的第一个示例直接进入数组以保护嵌入式换行符。第二个使用 printf 生成NUL终止数据,以便在不使用变量的情况下完成相同的操作。

如果您愿意使用变量,这很容易做到:

typeset -a entries
entries=(/etc/network.d/*(.)) # generate the list
echo ${entries#/etc/network.d/}  # strip the prefix from each one

你也可以在没有变量的情况下做到这一点,但隔离单个条目的额外内容有点难看:

# From the inside, to the outside:
# * glob the entries
#   * NUL terminate them into a single string
# * split at NUL
#   * strip the prefix from each one
echo ${${(0)"$(printf '%s\0' /etc/network.d/*(.))"}#/etc/network.d/}

或者,如果您打算使用子shell(例如前面示例中的命令替换),只需 cd 到目录,这样它就不是glob扩展的一部分了(另外,你不必重复目录名称):

echo ${(0)"$(cd /etc/network.d && printf '%s\0' *(.))"}

答案 1 :(得分:2)

克里斯·约翰森的答案充满了关于zsh的有用信息,但是没有提到在这种特殊情况下更简单的解决方案:

echo /etc/network.d/*(:t)

这是使用t 历史记录修饰符作为 glob限定符

答案 2 :(得分:1)

感谢您的建议,我们已经完成了对ZSH的更多阅读并在几天后回到问题中,我想我有一个非常简洁的解决方案,我想为您的利益分享。

echo $ {$(print /etc/network.d / *(。)):t}

答案 3 :(得分:0)

我习惯看到basename(1)剥离目录组件;此外,您可以使用echo /etc/network/*获取文件列表,而无需运行外部ls程序。 (运行外部程序可能比你想要的更慢;我没有为basename找到zsh-builtin,但这并不意味着没有。)

我希望这会有所帮助:

haig% for f in /etc/network/* ; do basename $f ; done
if-down.d
if-post-down.d
if-pre-up.d
if-up.d
interfaces