Fish-shell: && 不起作用

创建于 2012-06-19  ·  98评论  ·  资料来源: fish-shell/fish-shell

cd .. && pwd返回以下错误:

fish: Expected a command name, got token of type 'Run job in background'. Did you mean 'COMMAND; and COMMAND'? See the help section for the 'and' builtin command by typing 'help and'.
cd .. && pwd

显然我可以使用COMMAND; and COMMAND语法,但是如果fish 支持它会很好。

谢谢!

enhancement

最有用的评论

||也不错。

所有98条评论

||也不错。

我只是想表达另一种观点。
'||' 和 '&&' 是语法元素,而 'and' 和 'or' 是简单的命令。 这种方法简单而干净。
我认为引入额外的语法元素来实现现有功能并不是一个好主意。
它与 bash 不同,但没关系。

我也会投票支持 && 和 || 因为这是常用的语法糖,并且具有可用性真的很好。

+1 对 maxfl 的建议。

+1 对 maxfl 的建议。

Ruby 也有andor关键字。

+1

如果有人想接受这个,我不反对。

-1 实现 &&/|| 和 +1 到 maxfl。 我真的不明白为什么应该实施它。 它不是语法糖,在 bash 中它只是语法,而在fish 中这种语法不存在。 它也真的没用,因为像 ';or' 这样的语法糖和 '||' 的击键次数一样多。

我喜欢andor命令的简单性,但一个问题是它们使 if 语句变得奇怪。 例如:

if begin ; [ a = b ] ; and [ c = d ] ; end
   ...

相比

if [ a = b ] && [ c = d ]
    ...

有人有改进的想法吗?

if test a = b -a c = d # or [ ] syntax, but I didn't particularly liked it
    ...

但是,虽然这适用于test内置,但它在其他任何地方都不起作用。 让我们假设内置ab应该返回 true 以运行cd 。 然后,我们就可以这样写了。

and b
and begin
    c
    d
end

或者使用块语法和if

if begin
        a
        and b
    end
    c
    d
end

或者使嵌套有条件。

if a
    if b
        c
        d
    end
end

再说一次,我不确定需要这种 hack 的频率,但是searchco.de&&主要与test内置(或用于副作用)一起使用。

我不确定fish是否需要另一种仅在极少数情况下有用的语法。 感觉已经像[ ,除了必须留下来,因为它无论如何都是二进制的(就像test )。 感觉不是特别可疑,但它在这里,因为它是二进制的(与我很高兴鱼不支持的[[不同)。

有两种语法(或者在这种情况下,甚至是三种)会相当混乱。 我应该使用哪种语法?

if a
    b
end
a; and b
a && b

看起来&&是最短的,但这是事实的一半。 键入;and需要完全相同的击键次数(因为&涉及 Shift)。 添加&&会鼓励添加额外的语法(再说一次, and是一种特殊的解析方式,因为您可以在它之后插入诸如begin类的关键字,并且它们起作用)。

问题是我们有; and; or语法——新的语法感觉像是重复的。 它们已经有点神奇了(它们不仅仅是检查$status变量的 shell 脚本函数),所以如果将它们替换&&|| ,我就不会有问题

我不知道该怎么想。 我认为应该只有一种语法来做到这一点。 我喜欢; and; or ,但我不会有&&|| ,前提是旧的语法会被删除。 但考虑到向后兼容性,我更愿意继续使用; and; or 。 也许如果begin会更短(就像 bash 中的大括号)......但这不会让人觉得可疑。

为什么不支持内置 [[ 像 bash 那样呢? 它会更快(参见:内置回声)并且它会支持 && 和 || [[ 和 ]] 中的运算符来模拟和/或行为。

因为[[不是实际命令,所以它只存在于 bash 中。 问题是[[就像[ (主要是),除了它有特殊的解析规则以避免不必要的引用。 查看正交性定律和可发现性定律,了解为什么它不在鱼中。

事实上,我几乎可以肯定[不会因为可发现性定律和正交性定律而存在,但它确实存在,因为它在/usr/bin是二进制的。 test更可疑,因为您可以使用制表符补全来发现它。 但是阻塞二进制文件是相当随意的,所以不妨将它作为内置来实现。

例如,在 bash 中[[自动引用所有字符串。

[[ abc = $variable ]]

但这在鱼中是不需要的,因为不存在空白分割行为。 此外,它会自动引用&&||<>因为它是语法特征。 在鱼中, &&-a||-o<>甚至不存在。

它也有=~运算符。 在fish ,您可以为此使用安静的 grep。

echo $ANSWER | grep -qE '^y(es)?$'

此外, bash<>运算符。 他们检查任何字符串大于或小于其他字符串。 这很少有用。

而且,当使用=!=运算符时,您可以使用全局语法,就像使用正则表达式一样。 同样,为此使用安静的 grep。

[[ abc = a* ]]

此外, [[被定义为-e-nt-ot-ef! ,但是鱼已经在test内置了这些。

添加[[只会添加另一个关键字,这不会真正被发现,并且不会真正添加太多功能。 唯一有趣的功能是=~ ,但安静的 grep(或 Perl)可以做同样的事情,而无需添加新的语法。 此外,我们不应该将所有内容都添加到 shell 中。 我认为我们不需要内置正则表达式。

好吧,我的意思并不是说我们应该重新实现 bash 的[[内置函数,而是应该将它作为具有自己属性的句法构造引入。 我的意思是,fish 共享许多看起来像 bash 的关键字和结构,但它们是不同的,所以,我不明白这怎么会不是那样。

虽然,根据你所说的,也许实现我们自己的test会是一个更好的构造,虽然,重命名为类似cond ,就像fish 如何实现math内置expr 。 我们甚至可以实现像 < 和 > 之类的东西,但是,使用自然(数字)排序而不是字典排序,这样它就可以处理数字和字符串。

@Undeterminant builtin [[ vs builtin [ vs /bin/[ 微妙的差异在 bash 中已经令人困惑; 请不要通过添加 bash-[[ vs fish-[[ 细微差别!
此外,bash 的 [[ 的精神违反了正交性法则——它“修复”和/或但仅适用于构造支持的特定条件。

具有讽刺意味的是,bash 的if commands...; then ...; fi很容易承认鱼的和/或if...then 。 但我们不想要“那么”。 也许要解决的问题是让开始……结束更容易。

这是一个奇怪的想法(我完全不确定我喜欢它):

if (foo; and bar)
  ...
end

目前(...)在命令开始处是非法的; 自然的阅读是执行这个并将输出用作命令名称,但我们需要eval
如果我们确信我们永远不会允许直接读取,我们可以将裸(...)重新用于表示begin ...; end
在这个位置不捕获标准输出是不一致的——但看起来非常紧凑和干净。

我讨厌它的是if (...)乞求另一个含义:捕获输出并为其分配一些布尔解释。 例如if (math 2 \< 4)math不返回状态,它向标准输出打印 0 或 1。 一个重要的用途是if $saved_bool
我认为这是不切实际的——布尔含义没有单一的正确分配给字符串,特别是因为 0/1 被无可救药地混淆了。 但是当您第一次遇到if (...) ,这似乎是一个合理的猜测。

为兼容性起见,请提供 bash 和 zsh 中常见的运算符。 新用户越容易复制和粘贴他们以前的大部分 shell 功能,鱼的吸收率就越高。 我发现虽然我在很多方面都更喜欢鱼,但在经历了超过 15 年的 shell 自定义之后,这些愚蠢的小障碍中的一些只是让它变得麻烦而不是好处,而这些自定义实际上不应该成为支持的问题.

老实说,我不认为&&是一个“愚蠢的小障碍”。 如果您将鱼视为自己的语言而不是像 zsh 那样的“替换外壳”,那么学习并不难。 如果你阅读了关于fish如何从头到尾工作的教程,我认为这并不难理解。

command1; and command2这样的东西更清楚地表明andcommand2的条件执行,而不仅仅是command1command2之间的一些连接

但是@Undeterminant ,您不会像大多数人最初发现它时看到的那样看到它,等等。让这种感觉或熟练程度随着时间的推移而出现。 例如,我从旧的遗留配置中带来了数百行,老实说我没有时间立即转换需要转换的所有内容。 我发现奇怪的地方没有从鱼返回关于我的问题在我的旧配置中的位置的行号。

我可以理解您的观点,但对于想要做出改变并希望随着时间的推移而改变的人而不是通过一个大驼峰的人来说,这是有偏见的。 请不要误解,如果我不关心鱼并因此尝试提供输入,我现在肯定会跳回 zsh。 我觉得这种思想和推理对于为新来者进一步打开大门很重要。

所以是的,你对可读性是正确的,但让我们让旧的工作并给出警告而不是错误来让人们断奶。

@ylluminate你在自欺欺人。 即使 fish 支持&&您仍然不能只使用来自 bash 或 zsh 的配置,因为脚本语法的差异不仅仅是逻辑运算符。

确切地。 fish 在功能上是不同的,这意味着您不应该直接复制粘贴代码。 如果您的代码是用 bash 编写的,除非明确需要将其转换为 fish,否则只需将其保留为 bash; 它们是不同的语言。

所以
如果我做
命令 1 && 命令 2
在鱼中,它表明我输入
命令 1; 和命令 2

有人真的相信(在命令行中)第二个选项更简洁、更具未来感且更易于输入?

它更简洁,因为它建立在执行命令的现有语法之上,而不是引入新语法。

在 bash 中考虑:

foo & bar # executes foo in the background, then bar in the foreground
foo && bar # executes foo in the foreground, then executes bar if foo has a zero exit status
foo & bar && baz & qux # left as an exercise for the reader

这是我们希望通过使用命令而不是特殊语法来避免的那种废话。

这种设计决定肯定会产生成本,尤其是在 if 语句中,我们应该尽量减少这种成本。 但是我们应该从“让我们在其设计理念内找到改进鱼的方法”而不是“让我们找到使鱼更像其他贝壳的方法”的立场来处理它。

您的代码执行以下操作,对吗(假设您可以将&与块一起使用)?

foo &
if bar
    baz
end &
qux

对我来说,这似乎是人为的。 另外,如果&语法如此混乱,为什么不将background内置,或者其他什么?

我认为这确实是将背景设为内置的一个论点,尽管我并不是建议我们真的这样做。

; and; or是它们与管道的交互很差。 condition; and echo stuff | grep stuff不起作用,而condition && echo stuff | grep stuff起作用。 除了添加特殊语法之外,我认为没有办法解决这个问题。

and echo stuff | grep stuff似乎对我有用。 你能详细说明它是如何被破坏的吗?

@ridiculousfish这是我在尝试鱼时发现的情况。 or 表达式在 if 语句之外为真,但在 if 语句中使用时(似乎是?)为假。 除非我在这里遗漏了什么?

root@smogon-dev ~# test 0 = 1; or echo stuff | grep stuff
stuff
root@smogon-dev ~# echo $status
0
root@smogon-dev ~# if test 0 = 1; or echo stuff | grep stuff
                       echo Success
                   else
                       echo Failure
                   end
Failure

与 bash 比较:

~/smogon/bin$ [[ 0 == 1 ]] || echo stuff | grep stuff
stuff
~/smogon/bin$ echo $?
0
~/smogon/bin$ if [[ 0 == 1 ]] || echo stuff | grep stuff; then
> echo Success
> else
> echo Failure
> fi
stuff
Success

在这种情况下:

if test 0 = 1; or echo stuff | grep stuff

如果这样写可能会更清楚:

if test 0 = 1
    or echo stuff | grep stuff
    ...

or语句在 if 主体中! 由于布尔值是命令,因此它们没有特殊的优先级。

您可以使用开始/结束作为“括号”:

if begin; test 0 = 1; or echo stuff | grep stuff ; end
    ...

所以我认为它与管道无关,而是与优先级有关。

正如你在这个 bug 中看到的,关于 fish 是否应该支持布尔运算符有很多意见:)

所以,感谢你们在这里投入的精力。

我的目的不是要讨论哪些东西更好或不好。 这只是一个实用的东西。
和你们中的大多数人一样,我有自己的脚本要运行。 即使在非常简单的事情中,&& 条件也能保证命令成功(退出 0),而“;” 继续前进,不管发生了什么。 对? 所以,它们根本不一样。 我希望我们都同意这一点。 :)

所以,我有我的脚本,但它们都不适用于鱼。 是的,我经常使用&&。 但这也会发生在使用 bash 网络上的任何和平代码中,通常也使用 && 。 简而言之,问题是我不能再使用我的代码了! :D

我想知道......是否可以在鱼配置文件中建立一个函数或定义,以便仅修复此行为(意味着只是&&)并将其转回传统bash中? 是否可以? 合理吗? 可行吗?

同样,我同意使用“和”可能更好、更清晰。 但它不适用于我的代码,或者通常不适用于任何初学者的 bash 代码。 因此,与其更改已经编写的代码替换 && (...不会发生...并且很可能不会工作),如果有人想要或需要,让鱼理解传统的bash会更容易,不是吗?

所有最好的人,再次感谢您的努力!!

我们是否曾经接近完全兼容bash / zsh脚本? 根据我之前的评论,我放弃了fish ,因为我不会花时间转换我已经在我的 shell 环境中跨这么多工作站和服务器建立的所有基础设施。 如果我们离得更近,很想再试一次。 否则我只会继续兜售没有它。 谢谢。

@rhoconlinux更改 Fish 以支持&&不会使您的 bash 脚本工作。 还有更多的差异。

没看懂你的回答^_^
是否可以为 && 问题定义别名或函数?

@rhoconlinux不,您必须修改 Fish 解析器(在 C++ 中)。 我的观点是,如果 Fish 确实支持&& ,由于 Fish 和 Bash 之间的所有其他差异,您的 Bash 脚本仍将无法运行。

@kballard哎哟! 嗯……听到这个我很难过。 我现在明白了。 超级清晰。 :)

感谢您的超快速反馈。 我将使用 fish 来获得更好的日常体验,然后会为我的东西保留一个 bash 终端。

干杯! :+1:

如果&&是一个问题,那么处理它很容易。

sed 's/&&/; and /' ~/.bashrc > ~/.config/fish/config.fish

但这不太可能是您唯一需要做的事情。 你的意思是#522的实现。

我会说 && 兼容性的主要动机不是转换现有的
代码库,但从互联网复制粘贴。
例如,我看到一些sudo add-apt-repo... && sudo apt-get update && sudo apt-get install ...片段,只想复制粘贴但失败了。

这不是我们可以通过教育解决的问题——总会有的
要粘贴的片段,它们将使用标准的 [ba]sh 语法。
到目前为止, &&是我遇到的#1 问题。
export FOO=bar是 #2 但可以通过function export; set -x -g (echo $argv | sed 's/=/\n/'); end 。)

不过这不是什么大问题:我已经养成了打字的习惯
bash ,粘贴,Ctrl+D。
嗯,我很想添加一个键盘快捷键来运行当前/上一个
bash 下的命令行。

我对这个问题的两分钱:
我正在开发一个进行 shell 命令调用的部署工具 (https://github.com/andres-montanez/Magallanes),大多数用户和贡献者将使用 bash shell。 所以当然,这里和那里的 '&&' 用于将命令链接在一起。

有明显的解决方法(例如将所有命令显式传递给 bash)
但这带来了许多痛点。 一方面,可能会有奇怪的副作用(即 PATH 和其他变量的定义方式不同),这意味着为了这个目的而破解工具的一些核心部分,我需要将我的修复从一个版本合并到另一个版本每次我更新。

&& 只是 fish 不兼容的许多 bash 功能之一,但它可能是最基本和最常用的功能之一。 例如,上面的工具是用 PHP 编写的,所以任何复杂的东西都是用 PHP 完成的,并且只有基本的系统命令会传递给 shell。 在这样一个最小的用例中遇到语法不兼容是令人沮丧的。

我完全同意@cben所说的&&在我看来是一个特例,因为网上有数百个代码片段,其中复制和粘贴之间的唯一区别是对&&
虽然我同意,重要的是要考虑到fish 在语法等方面的进展情况。我确实认为这会让许多使用或想要使用 fish 的开发人员的生活变得更容易。 我知道这似乎是一个简单的将&&替换; and但是当我告诉其他人鱼有多棒时,它总是很烦人,而且让我感觉有点尴尬,但后来我不得不摆弄并更改一些关键字,他们通常会想为什么我要更改这么简单的东西。 然后我必须捍卫鱼,这不是促进鱼的好理由。
有时确实是最简单的事情可以产生最大的影响。
简而言之,我完全支持 bash &&语法。

我同意@Globegitter@cben所说的。 大量的脚本和程序依赖于&&|| 。 我在我的工作站上使用鱼壳,在编写脚本时具有跨壳兼容性会很好。

鉴于 Fish 脚本和 Bash 脚本之间存在许多显着差异,而不仅仅是&&|| ,为什么在此发表评论的所有人都认为让 Fish 接受&&会有任何意义吗? 如果您需要运行 Bash 代码片段,只需运行bash ,执行该片段,然后返回到 Fish。

我想很多人都想“转换”到鱼,但有基础设施可以带来。 例如,我在我的工作站上有 15 年的 shell 脚本(更不用说我也想在其上运行 fish 的其他服务器),我不想花时间进行转换。 我不介意在几个月的时间里四处闲逛并使事情以“鱼的方式”工作,但是我无法在我的工作流程中进行这种初始投资以更改为另一个外壳。

我相信如果一般的兼容性问题得到解决,fish 将会有大量用户涌入,但从其他从事 fish 开发的人所说的来看,这似乎不是该项目的优先事项。 正是出于这个原因,我一直密切关注这一点,因为如果景观在这方面发生变化,我最终想转向捕鱼。

关于仅根据需要运行bashzsh ,在我的情况下运行这些 shell 将是大量的,否则沿着这条路走下去是很愚蠢的。

@kballard我有一个理想的工作流程来处理我用fish 编写的 95% 的脚本:cmd+C 一个来自另一个来源的非常简单的脚本,cmd+tab 到 iTerm,cmd+v 和 Enter。 这就是我想要做的,没有额外的bash或其他什么,没有别的。 大多数情况下,阻止这些脚本使用此确切工作流程的唯一原因是存在&& 。 所以这就是为什么对我和我认为这里的大多数其他人解决这个问题会非常有用的原因。
如果你自己没有经历过,相信我,如果你的工作流程经常被打断,它确实会加起来并且真的会留在你的脑海中。

我喜欢鱼的其他一切,这就是为什么我不能切换回来,但这个简单的事情正是让它对我来说不是很棒的原因,我假设这里的其他一些人。

干得好。 PR #1633 登陆后,您可以将以下内容保存在~/.config/fish/functions/fish_user_key_bindings.fish

function handle_input_bash_conditional --description 'Function used for binding to replace && and ||'
    # This function is expected to be called with a single argument of either & or |
    # The argument indicates which key was pressed to invoke this function
    if begin; commandline --search-mode; or commandline --paging-mode; end
        # search or paging mode; use normal behavior
        commandline -i $argv[1]
        return
    end
    # is our cursor positioned after a '&'/'|'?
    switch (commandline -c)[-1]
    case \*$argv[1]
        # experimentally, `commandline -t` only prints string-type tokens,
        # so it prints nothing for the background operator. We need -c as well
        # so if the cursor is after & in `&wat` it doesn't print "wat".
        if test -z (commandline -c -t)[-1]
            # Ideally we'd just emit a backspace and then insert the text
            # but injected readline functions run after any commandline modifications.
            # So instead we have to build the new commandline
            #
            # NB: We could really use some string manipulation operators and some basic math support.
            # The `math` function is actually a wrawpper around `bc` which is kind of terrible.
            # Instead we're going to use `expr`, which is a bit lighter-weight.

            # get the cursor position
            set -l count (commandline -C)
            # calculate count-1 and count+1 to give to `cut`
            set -l prefix (expr $count - 1)
            set -l suffix (expr $count + 1)
            # cut doesn't like 1-0 so we need to special-case that
            set -l cutlist 1-$prefix,$suffix-
            if test "$prefix" = 0
                set cutlist $suffix-
            end
            commandline (commandline | cut -c $cutlist)
            commandline -C $prefix
            if test $argv[1] = '&'
                commandline -i '; and '
            else
                commandline -i '; or '
            end
            return
        end
    end
    # no special behavior, insert the character
    commandline -i $argv[1]
end

function fish_user_key_bindings
    bind \& 'handle_input_bash_conditional \&'
    bind \| 'handle_input_bash_conditional \|'
end

这将绑定&|并使其输入&&||自动将其转换为适当的; and / ; or ,从而允许您粘贴command one && command two形式的行并使其工作。

请注意,在 PR #1633 被接受之前,此脚本将适用于 _typing_ && / ||但不适用于粘贴它。

@kballard哇,这是个好消息! 太感谢了。

看起来这实际上并没有正确处理搜索模式(不确定寻呼机模式;我不清楚究竟是什么组成的)。 在搜索过程中点击&|终止搜索。 也就是说,我不知道如何处理。

我更新了脚本,修复了在多行命令中键入|&的错误修复。

@kballard我看到 PR 已经登陆。 所以你上面粘贴的脚本应该让&&与最新的主人一起工作?

是的,应该。 尝试一下,如果您有任何问题,请告诉我。

-凯文

2014 年 9 月 1 日凌晨 1 点 14 分,马库斯·帕杜雷克通知@github.com 写道:

@kballard我看到 PR 已经登陆。 所以你上面粘贴的脚本应该让&&与最新的主人一起工作?


直接回复此邮件或在 GitHub 上查看。

我用几天前发布的新2.1.1版本尝试了这个脚本,它似乎不起作用。 我必须等到2.2吗? 谢谢!

@pragmattica :2.1.1 是安全错误修复版本。 它没有添加任何新功能。

@xfix :好的。 谢谢你让我知道。 不能等到2.2!

太棒了:+1:

任何可用的运行更新日志? 看起来根CHANGELOG已经过时了。

@pragmattica现在鱼 2.2 出来了,我在 ubuntu 14.04 上试过了, echo 'test1' && echo 'test2';变成了echo test1 &; and echo 'test2';

fish_user_key_bindings.fish某处是否有问题? (我会尝试自己查看它,但我的fish/bash脚本知识有点不稳定)

编辑:但是,当您使用&&键入命令时,它似乎确实有效。 如果它之后发生在空间上可能会有点好,但这并不重要。 太好了,一半在工作:)

-1 到奇怪的符号:

if [[ a = b ]]; and [[ b = a ]]; or [[ c = b ]]; then echo hello; and echo world; done

+1 到简单符号:

if [[ a = b ]] && [[ b = a ]] || [[ c = b ]]; then echo hello && echo world; done

Aaahhh 我想我知道问题是什么@pragmattica命令commandline返回没有任何引号的缓冲区。 是的,似乎就是这样。 所以一旦https://github.com/fish-shell/fish-shell/issues/2210被修复,上面的脚本也应该被修复。

这还是开始考虑吗?

+1
这些符号并不奇怪,它们通常用于多种编程语言中的逻辑。
复制和粘贴兼容性是一个非常真实的论点,我支持。

我将成为坏人并结束这次讨论。 这将不会被实施。 关于希望能够“从 bash 脚本中剪切和粘贴命令”的重复声明让我特别困扰。 即使 fish 支持&&||运算符,也不能确保您可以简单地剪切和粘贴包含这些运算符的语句。 我们不想给人留下您可以这样做的印象。 老实说,如果您想要 bash/zsh 语法和行为,您应该使用这些 shell(或声称与它们兼容的替代方案)。

讨论的大多数其他想法都应该有自己的问题。 特别是实现一些由 ksh88(不是 bash)首先引入的[[ ... ]]行为可能有一些优点。 但可能通过增强内置的test命令或新命令而不是通过实现那些特殊标记。

我仍然对不支持 zsh 和 bash 的这种想法感到非常不安。 我能理解其中的逻辑,但我不同意。 前段时间我对鱼很感兴趣,但由于这种反对而退缩了。 如果我们作为开发人员有足够多的人希望看到该项目的实施,那么可能会有一些机会在这里分叉该项目。 很遗憾看到这种持续的阻力最终阻碍了对这样一件有趣作品的前进动力和接受度。

@ylluminate “支持 zsh 和 bash”你有什么想法? 您希望看到什么级别的兼容性?

我仍然对不支持 zsh 和 bash 的这种想法感到非常不安。 我能理解逻辑...

恐怕我不明白您让鱼支持 bash 和 zsh 功能的逻辑。 如果你想要 Java 为什么要使用 C++? 如果你想要 Perl 为什么要使用 Python? 正如@ridiculousfish刚刚问的那样,除了一些语法糖之外,fish 还必须支持什么才能让您开心? 什么时候鱼会变成另一个 bash 克隆?

PS,我从 1979 年开始以编程为生,从 80 年代中期开始使用 UNIX。 我用过的外壳数不胜数(例如,Bourne、Csh、Ksh88、Ksh93、Bash、Zsh、Xonsh)。 切换 shell 总是需要工作(这就是为什么我不会每五年左右做一次以上)。 当我这样做时,我不会抱怨我的新 shell 没有更改就无法运行我所有的旧脚本。

@krader1961 精彩的演讲。 在我的拙见中...

我不会一直在鱼中编写脚本(按顺序):

  1. 鱼的脚本很慢(比 mksh 慢)
  2. 一些奇怪的语法(例如; and; or对我来说看起来很难看)
  3. 与 posix 不兼容(我可以说语法很简单,但仍然需要时间学习)

好吧,只有当fish脚本比其他shell (例如mksh、bash)

另一方面,我使用鱼是因为:

  1. 启动时间比 zsh 快(但比 bash 慢)
  2. 默认启用了很多功能(语法高亮是最好的)
  3. 配置很好很简单(尤其是set -Ux

@ylluminate看着这个四年前的问题,我可以看到那些想像 bash 一样享受鱼的人是多么懒惰/忙碌,他们仍然懒惰/忙碌。 热心的人一直在制作自己的外壳(例如magicant/yash、elvish/elvish、michaelmacinnis/oh,还有我:-P)。 如果你想以一种不腥的方式做事,你可能需要一个不腥的外壳。

如果你真的考虑如何在鱼上实现&& ||并且让它不那么不腥,那么你可能会发现你只是在驱逐begin; end (看看 commit 594b460ba2d8dca59a3bfd282397c5f33aa9da6f 做了什么,柜台- ; and or扮演双重角色,非常有点丑),只得到一些糖。

@pickfire你能详细说明“鱼的脚本很慢吗?” 是否有任何测试可以让您得出这个结论?

FWIW 在我的测试中,fish 总体上比 bash 快,这得益于posix_spawn及其快速解析器,尽管在某些情况下它可能会更慢,例如alias

ivan<strong i="5">@alarmpi</strong> /tmp> echo 'echo test' > script
ivan<strong i="6">@alarmpi</strong> /tmp> time bash script
test
0.02user 0.01system 0:00.03elapsed 96%CPU (0avgtext+0avgdata 2776maxresident)k
0inputs+0outputs (0major+149minor)pagefaults 0swaps
ivan<strong i="7">@alarmpi</strong> /tmp> time mksh script
test
0.00user 0.00system 0:00.02elapsed 0%CPU (0avgtext+0avgdata 1420maxresident)k
480inputs+0outputs (2major+82minor)pagefaults 0swaps
ivan<strong i="8">@alarmpi</strong> /tmp> time fish script
test
0.07user 0.01system 0:00.09elapsed 85%CPU (0avgtext+0avgdata 4204maxresident)k
352inputs+0outputs (2major+231minor)pagefaults 0swaps

@ridiculousfish试想一下,与其他人相比,仅一个echo就已经很慢

@krader1961 @ridiculousfish IMO,一旦https://github.com/fish-shell/fish-shell/issues/2210发布,就可以关闭。 @kballard发布了一个非常简单的解决方案。

@pickfire感谢分享。 该测试测量的是启动开销,而不是echo 。 启动时间非常重要,但您无法从该测试中得出超出启动时间(主要取决于 config.fish)的结论。

这是一个不同的微基准测试:

> cat test.fish
for i in (seq 1000)
    ls > /dev/null
end

> time fish test.fish
        1.51 real         0.74 user         0.65 sys

> cat test.sh
for i in {1..1000} ; do
    ls > /dev/null
done

> time bash test.sh
        2.01 real         0.85 user         1.12 sys

在这里鱼赢了很多,但这主要是衡量 fork 与 posix_spawn 的差异。

我认为这里的一个结论是我们需要一个全面的基准测试套件。

@ridiculousfish这是你给我的基准:

> cat test.fish
for i in (seq 1000)
    ls > /dev/null
end
> time fish test.fish
4.18user 4.04system 0:22.62elapsed 36%CPU (0avgtext+0avgdata 4360maxresident)k
96inputs+0outputs (1major+321041minor)pagefaults 0swaps
> cat test.sh
for i in {1..1000} ; do
    ls > /dev/null
done
> time bash test.sh
0.70user 1.62system 0:09.81elapsed 23%CPU (0avgtext+0avgdata 2844maxresident)k
0inputs+0outputs (0major+154100minor)pagefaults 0swaps
> time mksh test.sh
0.00user 0.01system 0:00.04elapsed 24%CPU (0avgtext+0avgdata 1780maxresident)k
752inputs+0outputs (3major+203minor)pagefaults 0swaps

mksh似乎具有令人印象深刻的速度。

@pickfire fish 的ls是 Linux 上的一个函数,它可以做一些其他的事情来使输出更好,而 bash 没有这样做。 如果您想在 Linux 上进行苹果对苹果的比较,请使用command ls 。 (在达尔文,fish 的ls包装纸要薄得多 - 我应该指出这一点,但我忘记了。)

在您的测试中 mksh 的“令人印象深刻的速度”的解释是 mksh 没有大括号扩展,因此它只调用ls一次。 显然,调用ls一次比调用 1000 次要快得多。

这表明绩效衡量非常棘手 - 衡量与您认为正在衡量的不同的东西非常容易!

@ridiculousfish ,是否有任何理由使用ls函数是鱼脚本与command ls ? 在编写脚本期间输出并不重要。

好的,这次我按照你说的做了:

> cat test.fish
for i in (seq 1000)
    command ls > /dev/null
end
> time fish test.fish
0.66user 1.04system 0:08.08elapsed 21%CPU (0avgtext+0avgdata 4364maxresident)k
624inputs+0outputs (4major+113176minor)pagefaults 0swaps
> cat test.sh
for i in $(seq 1000) ; do
    ls > /dev/null
done
> time mksh test.sh
0.21user 0.65system 0:07.64elapsed 11%CPU (0avgtext+0avgdata 1884maxresident)k
0inputs+0outputs (0major+119632minor)pagefaults 0swaps
> time bash test.sh
0.15user 1.04system 0:08.66elapsed 13%CPU (0avgtext+0avgdata 2816maxresident)k
0inputs+0outputs (0major+150700minor)pagefaults 0swaps

最后, mksh仍然是最快的,现在我发现fishmksh快令人印象深刻。 如果fish具有内置的并行命令执行支持,我认为它会是最快的。

0.66 用户时间相当高。 我推测这是由于您的 config.fish 内容 - 定义别名等。 作为记录,这是我在我的 Linux 机器上看到的(最好是 3 个):

> time fish test.fish
0.15user 1.21system 0:01.33elapsed...
> time mksh test.mksh
0.12user 1.13system 0:01.24elapsed...
> time bash test.sh
0.18user 1.34system 0:01.47elapsed...

每个人都非常接近。

对于任何基准测试来说,将一种“预言外壳”合并到一些路径命令中可能会很有趣,这样我们就可以了解离操作系统可以提供的最大速度还有多远.

@ridiculousfish ,我的 config.fish 很短:

# Solarized colors
test $SHLVL = 2
and sh $HOME/.config/base16-shell/base16-solarized.dark.sh &
set fisher_home ~/.local/share/fisherman
set fisher_config ~/.config/fisherman
source $fisher_home/config.fish

好吧,因为它可能使用fisherman ,不确定它是否会减慢速度。 @bucaran是这方面的好人。 这一次,我清空config.fish (5 次重试的最佳结果):

> time fish test.fish; time mksh test.sh; time bash test.sh
0.62user 1.09system 0:07.28elapsed 23%CPU (0avgtext+0avgdata 4396maxresident)k
0inputs+0outputs (0major+108240minor)pagefaults 0swaps
0.21user 0.62system 0:06.92elapsed 11%CPU (0avgtext+0avgdata 1888maxresident)k
0inputs+0outputs (0major+116674minor)pagefaults 0swaps
0.29user 0.81system 0:07.78elapsed 14%CPU (0avgtext+0avgdata 2780maxresident)k
0inputs+0outputs (0major+145628minor)pagefaults 0swaps

@ridiculousfish @pickfire你能在另一个问题上聊天,这样我就可以阻止你的消息吗?

是的,很抱歉向此问题发送垃圾邮件。 @pickfire如果您想跟进一些您认为特别有趣或相关的基准,请随时打开另一个问题。

关于 bash 和 zsh 的兼容性,我个人并不期望完全兼容,但是随着兼容性的增加,fish 会变得更受欢迎。
即使不考虑脚本, &&||也很重要,因为它们非常常用于链接命令。 例如,我仍然遇到#2292 的问题。 我知道它可以被视为不是鱼虫,但事实是提高鱼的兼容性会修复它。

我在这里使用 maxfl,:-1: 将||&&作为鱼语法的一部分,如果这应该是一个受欢迎的投票。

Fish 不是 bash(或 zsh)。 除了与这些 shell 兼容之外,没有令人信服的理由来实现&&|| 。 与现状兼容是该项目的反目标。

@Nodd :您对问题 #2292 的引用实际上是为什么 fish 不应该实现该语法的一个示例。 这样做将是让人们认为fish 是POSIX(bash、zsh 等)克隆的又一步。 这只会产生其他要求,要求鱼类在其他地区表现得像贝壳一样。

对于所有正在寻找解决方案的人,从fish 2.3 开始,我可以确认最终有一个完全有效的解决方案。

只需做上面的答案提到的:

干得好。 PR #1633 登陆后,您可以将以下内容保存在 ~/.config/fish/functions/fish_user_key_bindings.fish 中:

function handle_input_bash_conditional --description 'Function used for binding to replace && and ||'
    # This function is expected to be called with a single argument of either & or |
    # The argument indicates which key was pressed to invoke this function
    if begin; commandline --search-mode; or commandline --paging-mode; end
        # search or paging mode; use normal behavior
        commandline -i $argv[1]
        return
    end
    # is our cursor positioned after a '&'/'|'?
    switch (commandline -c)[-1]
    case \*$argv[1]
        # experimentally, `commandline -t` only prints string-type tokens,
        # so it prints nothing for the background operator. We need -c as well
        # so if the cursor is after & in `&wat` it doesn't print "wat".
        if test -z (commandline -c -t)[-1]
            # Ideally we'd just emit a backspace and then insert the text
            # but injected readline functions run after any commandline modifications.
            # So instead we have to build the new commandline
            #
            # NB: We could really use some string manipulation operators and some basic math support.
            # The `math` function is actually a wrawpper around `bc` which is kind of terrible.
            # Instead we're going to use `expr`, which is a bit lighter-weight.

            # get the cursor position
            set -l count (commandline -C)
            # calculate count-1 and count+1 to give to `cut`
            set -l prefix (expr $count - 1)
            set -l suffix (expr $count + 1)
            # cut doesn't like 1-0 so we need to special-case that
            set -l cutlist 1-$prefix,$suffix-
            if test "$prefix" = 0
                set cutlist $suffix-
            end
            commandline (commandline | cut -c $cutlist)
            commandline -C $prefix
            if test $argv[1] = '&'
                commandline -i '; and '
            else
                commandline -i '; or '
            end
            return
        end
    end
    # no special behavior, insert the character
    commandline -i $argv[1]
end

function fish_user_key_bindings
    bind \& 'handle_input_bash_conditional \&'
    bind \| 'handle_input_bash_conditional \|'
end

@Globegitter

刚刚呢?

function sudo_bang_bang --on-event fish_postexec
    abbr !! sudo $argv[1]
end

@brj也把它放到~/.config/fish/functions/fish_user_key_bindings.fish ? 这对我来说似乎不起作用。

您需要获取此功能。 所以,你的选择是把它放在你的 config.fish 或把它放在 ~/.conf.d/[name-dont-matter].fish 中。

@brj :该功能的错误问题。 这是关于“&&”和“||”,而不是“!!” - 不同的东西。

@faho哈哈,你说得对。 我总是收到来自该问题的通知,所以我认为这是 sudo 的另一个案例 !!。

@Globegitter抱歉造成混乱!

以fish 为例发布建议的解决方法如何,以便用户可以方便地复制它? 错误消息可以很容易地增加提及这一点。 我一直在使用 && 的地方粘贴同一行(来自 gerrit code-review),因为它几乎适用于所有 shell(包括 windows cmd.exe,除了 unix-y shell)。 对我来说,上面提到的脚本是一个生产力助推器(我输入 bash -c "p​​aste here" 一段时间......)。

我该怎么办 && ? 有解决办法吗?

和上面一样的问题,我真的找不到任何办法

gcc test2.c -o a.out && ./a.out

在鱼。

gcc test2.c -o a.out; and ./a.out

@ivan尝试过,但它提供了“and”和“./a.out”作为 gcc 的参数。

//编辑:顺便说一句,我最终使用了bash脚本,因为这在fish中似乎是完全不可能的:(

gcc test2.c -lwlc -o a.out && (( sleep 2s; DISPLAY=:2 xterm ) & ./a.out)

我经常做这种“完全不可能”的事情。 也许在干净的鱼环境中尝试; and语法? 如果它不起作用,也许你的分号有问题? 您是将其输入到fish 中,还是从另一个程序中通过它?

@ivan输入。

对不起,可能是愚蠢的问题,但我该如何做括号? 我在文档中找不到关于它们的词,而且它不完全是 googleable 主题:(

gcc test2.c -lwlc -o a.out && (( sleep 2s; DISPLAY=:2 xterm ) & ./a.out)

@kozec我认为您只是在将您的物品组合在一起时遇到了麻烦。 你需要使用的是begin就像一个左括号(这就是我的想法)和end就像一个右括号。

gcc test2.c -lwlc -o a.out; and begin sleep 2s; env DISPLAY=:2 xterm; end & ./a.out

或缩进:

      gcc test2.c -lwlc -o a.out
         and begin sleep 2s
             env DISPLAY=:2 xterm
         end & ./a.out

@floam谢谢,这几乎有效。 但是 & 之前的内容不会发送到后台:(

最小的例子:

begin sleep 2s ; env DISPLAY=:2 xterm ; end & Xephyr :2

休眠 2 秒,然后启动 xterm,_then_ 为该 xterm 启动 XServer。 xterm ofc 在 XServer 准备就绪之前崩溃。

啊,对不起。 问题: https :

你会发现你可以通过这个你必须的地方解决它,而不是漂亮:

fish -c 'sleep 2s; env DISPLAY=:2 xterm' & Xephyr :2

当您有大量现有脚本时,为了开发、构建和 npm run-scripts 内部,切换是不合理的,特别是因为有些/大多数不在鱼上。 对于带有 shebang 的常规 bash 脚本,这当然不是问题。

&& 的好处(或“不错”)在于它不仅适用于 Linux 和 Mac 上的常规 shell,甚至适用于 Windows,这对于快速设置开发环境等非常有用。

无论如何都不是交易破坏者,但有点难以理解为什么添加它会是,要么?

好吧,这是一个相当愚蠢的论点。 为什么不为fish 编译器设置不同的“模式”? 即,您可以启用某种设置,其中您可以拥有“纯”鱼的东西,或者您可以与类似 bash 的外壳以及鱼主义兼容。 您甚至可以为其他 shell 设置不同“级别”的兼容性,以便您可以完全兼容、不兼容或介于两者之间。 我的意思是,在基本层面上,您至少可以为此实现某种源到源编译器。 或者使用 bash 代码并将其转换为鱼的内部中间表示。 在这方面你可以为翻译做各种事情。 如果我错了,请纠正我,但我相信 bash 等人的语言级概念。 vs. 鱼并没有天翻地覆的不同,对吧?

无论如何,这是我在这个问题上的 0.02 美元,这看起来真的很愚蠢,因为它建立在以下前提上:

"pure fish"
XOR
"compatibility with bash / becoming another bash clone"

当没有什么可以阻止在这两个概念之间取得中间立场时。

人们至少应该面对这样一个现实,即类似 bash 的贝壳比更深奥的贝壳(例如鱼)更标准和更受欢迎,因此确实应该有某种兼容层,使鱼成为能够站立的贝壳的任何现实机会-to-toe 与 bash 的广泛性和不引起兼容性问题。

...当没有什么可以阻止在这两个概念之间取得中间立场时。

除了某人(或一群人)投入超过 2,000 小时(一个人年)来编写必要的代码之外,别无他物。 我期待着查看您@ylluminarious 的拉取请求,以实现所有这些。 你所提议的相当于问为什么有人不能让 Python 也解释 PHP。 答案是理论上你可以有一个兼容性开关来这样做,但为什么要这样做呢?

在#4620 中实现。

此页面是否有帮助?
0 / 5 - 0 等级