zsh 文件名匹配/替换

发布于 2024-09-08 08:40:02 字数 616 浏览 5 评论 0原文

我正在尝试创建我的第一个 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

北笙凉宸 2024-09-15 08:40:02

一般注意事项:无需使用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' *(.))"}

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:

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

You can also do it without a variable, but the extra stuff to isolate individual entries is a bit ugly:

# 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/}

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):

echo ${(0)"$(cd /etc/network.d && printf '%s\0' *(.))"}
舟遥客 2024-09-15 08:40:02

Chris Johnsen 的答案充满了有关 zsh 的有用信息,但是它没有提到在这种特殊情况下有效的更简单的解决方案:

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

这是使用 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:

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

This is using the t history modifier as a glob qualifier.

剩一世无双 2024-09-15 08:40:02

感谢你们的建议,伙计们,在阅读了更多 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}

浅忆流年 2024-09-15 08:40:02

我习惯于看到 basename(1) 剥离目录组件;另外,您可以使用 echo /etc/network/* 来获取文件列表,而无需运行外部 ls 程序。 (运行外部程序可能会比您想要的更慢地完成;我没有找到用于基本名称的 zsh 内置函数,但这并不意味着没有。)

我希望以下内容能有所帮助:

haig% for f in /etc/network/* ;执行基本名称 $f ;完毕
if-down.d
if-post-down.d
if-pre-up.d
if-up.d
接口

I'm used to seeing basename(1) stripping off directory components; also, you can use echo /etc/network/* to get the file listing without running the external ls 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:

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文