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


10

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

$ !!:gs/\\/\/
bash: :gs/\\/\/: substitution failed

不知道为什么我无法替换。

我也尝试过:

$ !!:gs/\\/q

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

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


2
我现在没有Cygwin,但是我认为Windows路径正在运行...您是否试图用引号引起来?即cd 'C:\foo\bar'
-mpy

@mpy这实际上也可以!不知道我没有被替代所困扰。
Tanner Faulkner

1
“也将开放使用zsh的答案”。您的原著!!:gs/\\/\/确实在zsh中运作…
Kamil Maciorowski

@TannerFaulkner fc -s '\'='/' -1在Ubuntu LTS默认bash下工作。让我知道它是否也适用于Cygwin。我在答案中张贴了更多的单词。
Hastur

1
我认为这里的一般bash行为是在发生替换之前,将反斜杠作为转义符进行处理!!:gs/\\/\//。@Hastur fc -s '\'='/' -1获得预期的行为。这可能是bash中的错误。
quixotic

Answers:


6

正斜杠也是替换命令的定界符,因此必须将其作为替换字符串转义,以免提早结束替换

!!:gs/\\/\//

或更明确地如注释中所建议的那样,通过使用除斜杠之外的内容作为分隔符

!!:gs|\\|/|

但这似乎只能在tcsh(通常在我所在的shell中分配)起作用,bash因为无法转义在的第一个参数上似乎无效,所以我无法使命令起作用:s



1
请注意:!!:gs|\\|/可能更具可读性。
mpy

1
我无法使其正常工作。第一个参数:s似乎不是真正的正则表达式
固定为

4

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

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

fc  -s '\'='/' -1

一些解释

  • fc是bash 内置命令,用于从历史记录列表中列出或编辑并重新执行命令。
  • -1将接受历史记录中的最后一条命令。请注意,甚至!!将(从中读取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...

  • 模式将由外壳读取,因此我们必须用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
    由于“历史记录”扩展是在读取整行后立即执行的,因此在shell将其分解为单词之前,您可能会倾向于将其用于某种或多或少平淡的bashism,例如,从(可能是添加:p:q,、"",解析等...)

    !!:0 ${_//\\/\/}

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

结论

历史记录扩展将历史记录列表中的单词引入到输入流中,从而使重复命令,将上一个命令的参数插入当前输入行变得容易,或者快速修复了先前命令中的错误。

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


恶心:一个小实验

我已经histverify在外壳中启用了...

shopt -s histverify
echo C:\Foo\Bar
!!:s|C|D| {1,2}A

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

echo D:\Foo\Bar {1,2}A

然后我再按Enter一次

D:FooBar 1A 2A

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


2

您可以sed用来替代并执行结果。

这种命令有几种可能的变体,但以我的观点,仅此一种有效:

A=$(echo "!!\\" | sed 's,\\,/,g');eval $A

\\被添加到!!在壳体以反斜线终止的最后一个命令。没有它,外壳会感到困惑,并要求继续生产。

您也可以将其作为bash函数添加到文件中~/.bashrc

function slash {
   A=$(history | tail -n 2 | head -n 1 | cut -c 8- | sed 's,\\,/,g')
   eval $A
}

这是我在Windows上的Bash上的工作方式:

重击

为了解释A=命令如何将正确的值分配给shell变量A

  • tail从命令历史记录中获取最后两行,并给出cd \mnt\c其后跟的行slash。的部分history | tail -n 2也可以写成history 2
  • head 第一行是 cd \mnt\c
  • cut 切断由提供的行号 history
  • sed 用斜杠替换所有反斜杠
  • eval 执行变量的内容 A

嗨,哈利。抱歉地说,在我的GNU bash版本4.3.11(1)上A=$(echo "!!\\" | sed 's,\\,/,g');eval $A,该命令以反斜杠终止时不起作用。C:\Foo\Bar\ 如您所说,您被迫在其他地方添加一个空格,例如,shell将等待该行的继续。您也可以按两次Enter键。在第一种情况下,您会获得C:/Foo/Bar /(在/; 之前有一个空格;在第二种情况下,它将产生一个错误。该函数运行正常
。– Hastur

我之所以编写该函数,是因为(1)使用起来容易得多,并且(2)单行代码似乎过于依赖于实现。
harrymc '17

-1

我认为您无法做到这一点。您需要再次复制/粘贴。

该问题与斜线蜂也与替代命令分隔符无关,因为替代命令接受任何分隔符。问题在于要替换的反斜杠,它们已经被视为其右边的简单无用的字符转义符。

因此,当您调用替代命令时,反斜杠已从源头消失。只需按原样(!!)重新调用该命令即可。而不是打印完全相同的命令c:\foo,它将执行命令减去已处理的反斜杠,结果为c:foo

显然,您找不到或替换丢失的字符。尝试这样做将引发错误。


1
好。最终这是错误的,因为此测试实际上有效:echo c:\Foo其后是!!:gs,F,\\f,。但是,用反斜杠转义本身代替似乎很痛苦。
A. Loiseau
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.