我已将命令cd C:\foo\bar\
从 PowerShell 复制到 Cygwin,并愚蠢地希望它能够执行。我现在正尝试运行替换,将所有替换\
为/
:
$ !!:gs/\\/\/
bash: :gs/\\/\/: substitution failed
不确定为什么我会收到替换失败的消息。
我也尝试过:
$ !!:gs/\\/q
只是想看看替换是否是问题所在。不是。现在我很好奇!
为什么我会收到“替换失败”的消息?
答案1
正斜杠也是替换命令的分隔符,因此必须将其转义为替换字符串,以免提前结束替换
!!:gs/\\/\//
或者更明确地如评论中所建议的那样,使用斜线以外的其他符号作为分隔符
!!:gs|\\|/|
但这似乎只在(我所在位置通常分配的 shell)中起作用tcsh
,我无法让命令起作用,bash
因为似乎转义对第一个参数不起作用:s
答案2
简短回答:内置fc
(修复命令)的 bash
fc
是命令,内置在 bash shell 中,用于编辑和重新执行历史命令。
它是也出现在 CygWin 上并且它可以在我测试过的所有 Linux 发行版上运行:
fc -s '\'='/' -1
一些解释
fc
是 bash内置命令列出或编辑并重新执行历史列表中的命令。-1
将采用历史记录中的最后一条命令。请注意,even 的!!
定义(从 读取man bash
)为!! Refer to the previous command. This is a synonym for
!-1“”。-s
用另一个模式替换一个模式。这次来自help fc
(内置命令 sohelp
):使用 `fc -s [pat=rep ...] [command]' 格式,在执行替换 OLD=NEW 之后,将重新执行 COMMAND。
好的,他们的意思
pat=rep
是而不是OLD=NEW
......- 这些模式将被 shell 读取,因此我们必须使用 quote:
'\'
和 来保护它们'/'
。
关于为什么会出现“替换失败”的更多内容
似乎对于s
修饰符尚未实现反斜杠字符的替换\
,即转义字符。为确保万无一失,我们应该查看 bash 历史扩展的 gnu 版本代码(但有上述命令可以获取您尝试执行的操作……所以我偷懒....)。
一些说明:
我们被引导去认为它将适用于我们发现的每个与 一起使用的 RegEx
sed
,但这并不能保证。反斜杠是扩展的转义字符,问题就在这里。此外,扩展的行为与选项有关shopt
,所以我们应该开始逐个查看...当您将字符串粘贴
cd C:\Foo\Bar
到 bash shell 中时,它将被展开,并在解释器中显示为cd C:FooBar
;以这种形式,它$_
也将存储在内部变量中。
如果您将cd "C:\Foo\Bar"
或粘贴到变量cd 'C:\Foo\Bar'
中,$_
您应该会发现C:\Foo\Bar
。
由于历史记录扩展是在读取完整行之后立即执行的,在 shell 将其分解为单词之前,您可能会想开始将它与一些巴什主义或多或少简单,例如,从中得出一些推导(可能添加:p
或:q
,""
解析等等......)!!:0 ${_//\\/\/}
此刻我们要记住,现在并不安全开始玩路径和文件名,特别是如果它们来自 Windows 剪贴板(一般阅读页面为什么不是解析
ls
?,它本质上与使用制表符、空格和换行符作为文件名和目录名的正确字符的可能性有关……)。
此外,当你粘贴用鼠标捕获的文本,您也可以粘贴前导空格。这可以避免您的命令在历史记录中结束(这取决于 shell 选项...)。如果是这样,您的后续!!
命令将不受控制...(请参阅中的示例另一个答案)。这是一个不必要的有形风险。
结论
历史扩展将历史列表中的单词引入输入流,让一切变得简单重复命令,将前一个命令的参数插入到当前输入行,或者快速修复前一个命令中的错误。
如果这不容易,我就会开始认为我们做错了什么;-)
令人厌烦:一个小实验
然后我已经histverify
在 shell 中启用了......
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
在之前处理的历史扩展中生成的括号扩展, 所以首先,并且它似乎证实s
历史修改器没有(尚未)将字符替换处理\
为真正的正则表达式......
答案3
您可以使用sed
来替换并执行结果。
这样的命令有几种可能的变体,但在我的 bash 中只有这一个有效:
A=$(echo "!!\\" | sed 's,\\,/,g');eval $A
如果最后一条命令以反斜杠结尾,则\\
在 is 后面添加 is 。如果没有它,shell 会感到困惑,并要求继续执行该行。!!
您还可以将其作为 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
答案4
我认为你不能这样做。你需要再次复制/粘贴。
这个问题与斜线作为替换命令分隔符无关,因为替换命令可以接受任何分隔符。问题在于要替换的反斜线,它们已经被视为右侧字符的简单无用转义符。
因此,当您调用替代命令时,反斜杠已从源中消失。只需尝试按原样重新调用命令(!!
)。它不会打印包括 的完全相同的命令c:\foo
,而是执行命令减去已处理的反斜杠,结果为c:foo
。
显然,您无法找到或替换缺失的字符。尝试这样做将引发错误。