从 Fish 中的路径中提取文件夹名称 Shell

Extracting a folder name from path in Fish Shell

我有多个这样的目录

~/project/foo/Debug
~/project/bar/Debug
... and so on

文件夹 projectDebug 是常量。

我在调试目录中,foobar是项目名称。当我在 ~/project/bar/Debug 中时,是否可以将变量设置为字符串 bar,当我在目录 ~/project/xxxxx/Debug 中时,是否可以将该变量设置为 xxxxx

当前目录可通过 PWD 变量获得,因此您可以测试:

set -g string # define variable globally
if test $PWD = ~/project/foo/Debug
     set string foo
else if test $PWD = ~/project/bar/Debug
     set string bar
end

当然,如果项目超过三个,或者列表随时间发生变化,那会变得很笨重,所以你可以使用 fish 内置的 string 工具对其进行匹配和替换。

set -g string
if string match -q '/projects/*/Debug'
     set string (string replace -r '.*/projects/([^/]+)/Debug' '' -- $PWD)
end

我怀疑您真正想要的是在提示中显示您的项目名称而不是工作目录。如果是这样并且你使用git,你可以使用这个

function prompt_pwd --description 'Print the current working directory, shortened to fit the prompt'
    set -q argv[1]; and switch $argv[1]
        case -h --help
            __fish_print_help prompt_pwd
            return 0
    end

    # This allows overriding fish_prompt_pwd_dir_length from the outside (global or universal) without leaking it
    set -q fish_prompt_pwd_dir_length; or set -l fish_prompt_pwd_dir_length 1

    set -l tmp
    set -l gitdir
    # Replace everything up to the vcs root with [rootname]
    # under the assumption that that is the name of the "project".
    # TODO: On my machine, it seems that the last two components are the safer bet, e.g.
    # kwin/tiling
    # exercism/cli (go)
    # elves/elvish (go)
    # new/exa-git (aur)
    # dev/fish-shell
    #
    # Either that, or a more robust system of abbreviations,
    # a non-hacky solution for which needs dictionaries.
    if set gitdir (git rev-parse --show-toplevel ^/dev/null)
        set tmp (string replace -- $gitdir '' $PWD)
        # Underline the "project name"
        # FIXME: The coloring here will leak, but I can't see a way to just undo underlining.
        set gitdir \[(set_color -u)(string replace -r '.*/' '' -- $gitdir)(set_color normal; set_color $fish_color_cwd)\]
    else
        # Replace $HOME with "~"
        # Only if we're not in a gitdir, otherwise $HOME/dev/$HOME would give weird results.
        set realhome ~
        # FIXME: This will give weird results if any special regex chars are in $HOME,
        # but it should be a regex match because we only want it replaced at the beginning of the string.
        set tmp (string replace -r '^'"$realhome"'($|/)' '~' $PWD)
    end
    # The test will return false if $fish_... is non-numerical,
    # and the replace will not replace anything, so the PWD will be unshortened.
    # This is okay.
    if [ $fish_prompt_pwd_dir_length -eq 0 ]
        echo -s $gitdir $tmp
    else
        # Shorten to at most $fish_prompt_pwd_dir_length characters per directory
        # but only after the gitdir
        echo "$gitdir"(string replace -ar '(\.?[^/]{'"$fish_prompt_pwd_dir_length"'})[^/]*/' '/' $tmp)
    end
end

这也可以适用于例如mercurial 或类似的,虽然根据我的经验,mercurial 启动起来相当慢,因此不是你希望每次提示都发生的事情。

保存在~/.config/fish/functions/prompt_pwd.fish.

正如 faho 在他的回答中指出的那样,如果效率至关重要,则可以使用最近添加的 string 内置函数。但是,在这种情况下,我可能会使用传统的解决方案,因为它的清晰度和简单性:

set var (basename (dirname $PWD))

如果您不想支付两个非常便宜的外部命令的费用,我会这样做而不是使用正则表达式:

set components (string split -- / $PWD)
set var $components[-2]

您甚至可以在一条语句中做到这一点:

set var (string split -- / $PWD)[-2]