在最后一个命令中用反斜杠替换正斜杠

rtf*_*rtf 11 cygwin bash regex

我已将命令cd C:\foo\bar\从 PowerShell复制到 Cygwin 并愚蠢地期望它执行。现在我想运行一个替代全部更换\/

$ !!:gs/\\/\/
bash: :gs/\\/\/: substitution failed
Run Code Online (Sandbox Code Playgroud)

不知道为什么我的替换失败了。

我也试过:

$ !!:gs/\\/q
Run Code Online (Sandbox Code Playgroud)

只是看看更换是否有问题。它不是。现在我很好奇!

为什么我会“替换失败”?

inf*_*xed 6

正斜杠也是替换命令的分隔符,因此您必须将其作为替换字符串进行转义,以免提前结束替换

!!:gs/\\/\//
Run Code Online (Sandbox Code Playgroud)

或者更清楚地按照评论中的建议,使用斜杠以外的其他东西作为分隔符

!!:gs|\\|/|
Run Code Online (Sandbox Code Playgroud)

但这似乎只适用于tcsh(通常分配给我的shell),我无法使用命令,bash因为它似乎转义不适用于第一个参数:s


Has*_*tur 5

简短回答:bash的内置fc(修复命令)

fc内置在bash shell 中的命令,用于编辑和重新执行历史命令。
它也存在于 CygWin 上,并且适用于我测试过的所有 Linux 发行版:

fc  -s '\'='/' -1
Run Code Online (Sandbox Code Playgroud)

一些解释

  • fc是 bash内置命令,用于从历史列表中列出或编辑和重新执行命令。
  • -1将执行历史记录中的最后一个命令。请注意, even!!被定义(读取自man bash)为

    !! Refer to the previous command. This is a synonym for!-1 '。

  • -s用另一个模式替换一个模式。这次来自help fc(内置命令 so help):

    使用`fc -s [pat=rep ...] [command]'格式,在执行替换OLD=NEW后重新执行COMMAND。

    好吧,他们的意思是pat=rep而不是OLD=NEW......

  • 这些模式将由 shell 读取,因此我们必须使用 quote:'\'和来保护它们'/'

关于为什么您会“替换失败”的更多信息

似乎对于s 修饰符还没有实现反斜杠字符的替换,即转义符\。可以肯定的是,我们应该看到例如 bash 历史扩展的 gnu 版本的代码(但是上面的命令可以获取您正在尝试执行的操作...所以我认为它很懒惰....)。

一些注意事项:

  1. 我们认为它适用于我们发现使用的每个 RegEx sed,但不能保证。反斜杠是扩展的转义字符,问题就在这里。此外,扩展的行为与shopt选项有关,因此我们应该开始逐案查看......

  2. 当您将字符串粘贴到cd C:\Foo\Barbash shell 中时,它将被扩展,并且在解释器中显示为cd C:FooBar; 在这种形式中,它也将存储在$_内部变量中。
    如果您改为粘贴cd "C:\Foo\Bar"cd 'C:\Foo\Bar'$_ 变量中,您应该找到C:\Foo\Bar.
    由于 History 扩展是在读完完整行后立即执行的,在 shell 将其分解成单词之前,您可能会开始使用它或多或少地带有一些bashism或多或少简单,例如,从(可能添加:p:q"",解析等等...)

    !!:0 ${_//\\/\/}
    
    Run Code Online (Sandbox Code Playgroud)

    现在要记住开始使用路径和文件名是不安全的,特别是如果它们来自 Windows 剪贴板(一般阅读页面为什么解析ls,它本质上与使用选项卡的可能性有关,空格和换行符作为文件名和目录名的正确字符......)。
    此外,当您粘贴鼠标捕获的文本时,您也可以粘贴前导空格。这可能会避免您的命令在历史记录中完成(这取决于 shell 选项......)。如果是这样,您的以下!!命令将是不受控制的命令...(请参阅另一个答案中的示例)。这是一种不必要的有形风险

结论

历史扩展将历史列表中的单词引入输入流,使重复命令、将前一个命令的参数插入当前输入行或快速修复前一个命令中的错误变得容易

如果这并不容易,我开始认为我们做错了什么 ;-)


令人作呕:一个小实验

我已经histverify在shell中启用了...

shopt -s histverify
echo C:\Foo\Bar
!!:s|C|D| {1,2}A
Run Code Online (Sandbox Code Playgroud)

然后我按下Enter并作为经过验证的扩展我发现

echo D:\Foo\Bar {1,2}A
Run Code Online (Sandbox Code Playgroud)

然后我再按Enter一次,它回响

D:FooBar 1A 2A
Run Code Online (Sandbox Code Playgroud)

这似乎表明substitution failed是在Brace 扩展之前处理的历史扩展中生成的,所以首先,它似乎确认s历史修饰符没有(尚未)将\字符的替换处理为真正的正则表达式。 ..