【问题标题】:How to abort a fish script from a lower-level function?如何从较低级别的函数中止鱼脚本?
【发布时间】:2017-06-11 13:44:33
【问题描述】:

给定一个仅打印“foo”、帮助或错误的 fish 脚本 foo.fish

function foo
  __parse_args $argv[1]
  echo foo
end

function __parse_args --argument option
  if test -z $option
    return  # No option to parse, return early
  end

  switch $option
    case -h --help
      echo "Shows this help and exits"
      return 0  # How can we exit 0 instead of return?
    case -\*
      echo "Error: '$option' not a valid option"
      return 1  # How can we exit 1 instead of return?
  end
end

实际行为:

↪ foo -h
Shows this help and exits
foo

预期行为:

↪ foo -h
Shows this help and exits

return 手册说它会停止当前的内部函数并设置函数的退出状态。

在嵌套函数调用中,我们如何使用适当的退出代码提前退出脚本?

请注意,我们不能使用 exit,因为它会退出 shell 而不仅仅是脚本。

【问题讨论】:

  • “退出 shell 而不仅仅是脚本”是什么意思?除非您使用 source. 获取脚本,否则脚本将在其自己的 shell 中运行。

标签: shell return abort fish


【解决方案1】:

除非您通过source. 运行脚本,否则它会在自己的新shell 进程中运行。 exit 命令将终止该进程并返回调用脚本的父 shell; exit 的参数将是退出后该父进程内的$status 的值。

如果您实际上是在交互式 shell 中定义 foo 函数(通过 source. 或在 shell 提示符下键入/粘贴,或在 .fishrc 或 ~/. config 或其他)然后__parse_args 无法从foo 返回。 foo 必须显式检查__parse_args 的返回值(即在调用__parse_args 后检查$status),然后在适当时立即返回。这也意味着在处理 --help 时,由 __parse_args 决定返回不同的值,而不是在其他情况下成功。

但是,除非 foo 的实际操作涉及对您的 shell 环境进行一些修改,否则我建议将其设为可执行脚本文件而不是函数,例如将其放入名为 foo 的文件中命令搜索$PATH:

#!/usr/bin/env fish
function foo
  __parse_args $argv[1]
  echo foo
end

function __parse_args --argument option
  if test -z $option
    return  # No option to parse, return early
  end

  switch $option
    case -h --help
      echo "Shows this help and exits"
      exit 0  # How can we exit 0 instead of return?
    case -\*
      echo "Error: '$option' not a valid option"
      exit 1  # How can we exit 1 instead of return?
  end
end

foo $argv

这有预期的结果:

> foo
foo
> foo -x
Error: '-x' not a valid option
[1]> foo -h
Shows this help and exits
>

【讨论】:

  • 在示例脚本中,例如将return 0更改为exit 0,然后复制粘贴函数并执行foo -h。您运行它的外壳将关闭。根据exit 手册,它将退出(鱼)外壳。只有在获取文件时调用 exit 才会跳过文件的其余部分,而不是退出 shell 本身。
  • 是的,但是在提示符下复制和粘贴与source. 相同——您在交互式shell 中定义函数,然后运行该函数。没有办法退出fish 中的多级函数调用。我建议把它做成一个脚本。
  • ~/.config/fish/functions/foo.fish 创建脚本仍然会退出shell。
  • 请注意,短路建议只处理失败情况(从错误返回 1),而不是正常情况(从帮助返回 0)。
  • 是的。调用者需要$status 上的另一个开关/案例来做正确的事情。
【解决方案2】:

很晚才出现,但是 Mark 提供的脚本仍然退出 Dennis 的 shell 的原因似乎是它被放置在 ~/.config/fish/functions/foo.fish 中,这是函数路径,而不是可执行路径。这意味着 foo 函数被自动加载和执行,而不是 foo 脚本本身。在这种情况下,“退出”是中止函数(以及 shell),而不是脚本的进程。

将脚本放在 PATH 中,而不是函数路径中,应该允许它工作。

或者,如果您确实想将其作为自动加载函数运行,以下内容有点复杂,但可以作为 ~/.config/fish/functions 中的脚本/函数运行。当然,脚本的名称必须是 foo.fish。本质上,它是一个将其包含文件作为脚本调用的函数。

#!/usr/bin/fish

function foo
  chmod 740 (status --current-filename)
  fish -c (status --current-filename)" __exec_script $argv"
end

if test "$_" = "source"
  or test -z "$argv"
  or ! test "$argv[1]" = "__exec_script"
  foo $argv
  exit
end

function __parse_args --argument option
  if test -z $option
    return  # No option to parse, return early
  end

  switch $option
    case -h --help
      echo "Shows this help and exits"
      exit 0  # How can we exit 0 instead of return?
    case -\*
      echo "Error: '$option' not a valid option"
      exit 1  # How can we exit 1 instead of return?
  end
end

set argv $argv[2..-1] # Remove first argument, the __exec_script magic token
__parse_args $argv[1]
echo foo

chmod 行不是必需的,当然,如果你在安装脚本时自己做的话。

生成的文件可以作为脚本调用:

~/.config/fish/functions/foo.fish      # Results in "foo"
~/.config/fish/functions/foo.fish -h   # Results in "Shows this help and exits"
~/.config/fish/functions/foo.fish -i   # Results in "Error: '-i' not a valid option"

作为一个函数...

foo              # Results in "foo"
foo -h           # Results in "Shows this help and exits"
foo -i           # Results in "Error: '-i' not a valid option"

或来源...

source ~/.config/fish/functions/foo.fish         # Results in "foo"
source ~/.config/fish/functions/foo.fish -h      # Results in "Shows this help and exits"
source ~/.config/fish/functions/foo.fish -i      # Results in "Error: '-i' not a valid option"

...结果都一样:

【讨论】:

    【解决方案3】:

    __parse_args 中,您可以为-h 返回1,然后

    function foo
        __parse_args $argv[1]
            or return $status
        echo foo
    end
    

    这为-h 提供了非零返回状态,但这可能没什么大不了的。

    【讨论】:

      猜你喜欢
      • 2010-11-25
      • 2020-02-01
      • 2021-10-22
      • 2016-04-28
      • 2018-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-20
      相关资源
      最近更新 更多