Copiei o comando cd C:\foo\bar\
do PowerShell para o Cygwin e esperançosamente esperei que ele fosse executado. Agora estou tentando executar uma substituição para substituir tudo \
por /
:
$ !!:gs/\\/\/
bash: :gs/\\/\/: substitution failed
Não sei por que estou recebendo a substituição falhou.
Eu também tentei:
$ !!:gs/\\/q
Só para ver se a substituição foi o problema. Não é. Agora estou curioso!
Por que estou recebendo "falha na substituição"?
cd 'C:\foo\bar'
!!:gs/\\/\/
funciona em zsh…fc -s '\'='/' -1
funciona no bash padrão do Ubuntu LTS. Deixe-me saber se ele funciona com Cygwin também. Postei mais palavras na resposta.!!:gs/\\/\//
. @Hasturfc -s '\'='/' -1
obtém o comportamento esperado. isso pode ser um bug no bash.Respostas:
uma barra é também o delimitador do seu comando substituto; portanto, você deve escapar dela como a string de substituição para não terminar a substituição antecipadamente
ou mais claramente, conforme sugerido nos comentários, usando algo além de barra como delimitador
Mas isso parece funcionar apenas
tcsh
(o shell geralmente designado onde estou), não consigo executar o comandobash
, pois parece que escapar não funciona no primeiro argumento de:s
fonte
!!:gs|\\|/
pode ser um pouco mais legível.:s
não parece ser um regex realResposta curta: o builtin
fc
(comando de correção) do bashfc
é o comando, incorporado no shell bash, criado para editar e reexecutar comandos do histórico.Também está presente no CygWin e funciona em todas as distribuições Linux nas quais testei:
Algumas explicações
fc
é a festa built-in comando à lista ou editar e re-executar comandos a partir da lista do histórico.-1
assumirá o último comando da história. Observe que even!!
é definido (lido deman bash
) como-s
para substituir um padrão por outro. Desta vez, a partir dehelp fc
(comando incorporadohelp
):Ok, eles querem dizer em
pat=rep
vez deOLD=NEW
...'\'
e'/'
.Algumas palavras mais sobre por que você está recebendo "falha na substituição"
Parece que para o
s
modificador ainda não está implementada a substituição do caractere de barra invertida\
, que é o escape. Para ter certeza de que deveríamos ver o código, por exemplo, da versão gnu da expansão do bash history (mas havia o comando acima para obter o que você estava tentando fazer ... então eu tomo preguiçoso ....).Algumas notas:
Somos levados a pensar que ele funcionará com cada RegEx que encontramos trabalhando
sed
, mas não é garantido. A barra invertida é o caractere de escape da expansão e o problema está aqui. Além disso, o comportamento da expansão está relacionado àsshopt
opções, portanto, devemos começar a ver caso a caso ...Quando você cola a string
cd C:\Foo\Bar
no shell bash, ela será expandida e aparecerá para o intérprete comocd C:FooBar
; neste formulário, ele também será armazenado na$_
variável interna.Se você colou
cd "C:\Foo\Bar"
oucd 'C:\Foo\Bar'
na$_
variável você deve encontrarC:\Foo\Bar
.Como a expansão History é executada imediatamente após a leitura de uma linha completa, antes que o shell a divida em palavras, você pode ficar tentado a usá-la com algum basismo mais ou menos claro, por exemplo, com alguma derivação de (talvez adicionar
:p
ou:q
,""
, análise e assim por diante ...)É o momento de lembrar que não é seguro começar a brincar com nomes de arquivos e caminhos , principalmente se eles vierem da área de transferência do Windows (leia em geral a página Por que não analisar
ls
?) , Está essencialmente relacionado à possibilidade de usar a guia, espaços e novas linhas como caracteres corretos para os nomes dos arquivos e dos diretórios ...).Além disso, quando você cola um texto capturado com o mouse , também pode colar um espaço à esquerda. Isso pode evitar que o seu comando termine no histórico (depende das opções do shell ...). Nesse caso, seu
!!
comando a seguir não será controlado ... (veja um exemplo em outra resposta ).Esse é um risco tangível desnecessário .Conclusão
Se não é fácil, começo a pensar que estamos fazendo algo errado
;-)
Ad nauseam: um pequeno experimento
Eu ativei
histverify
no shell então ...então eu pressiono Entere como expansão verificada eu acho
então eu pressiono Enternovamente e ecoa
Isso parece indicar que isso
substitution failed
é gerado na expansão do histórico processada antes da expansão do Brace , então, primeiro de tudo , e parece confirmar que os
modificador do histórico (ainda) não processou (ainda) a substituição do\
personagem como um regex real. ..fonte
Você pode usar
sed
para substituir e executar o resultado.Existem várias variantes possíveis para esse comando, mas no meu bash apenas este funcionou:
O
\\
é adicionado ao!!
is no caso do último comando terminar com uma barra invertida. Sem ele, o shell ficará confuso e solicitará a continuação da linha.Você também pode adicionar isso como uma função bash no arquivo
~/.bashrc
:Aqui está como isso funciona no meu Bash no Windows:
Para explicar como o
A=
comando atribui o valor correto à variável do shellA
:tail
pega as duas últimas linhas do histórico de comandos, que fornece as linhas decd \mnt\c
seguido porslash
ele mesmo. A parte dehistory | tail -n 2
também pode ser escrita comohistory 2
.head
pegue a primeira linha que écd \mnt\c
cut
corta o número da linha fornecido pelahistory
sed
substitui todos os anti-barras por barraseval
executa o conteúdo da variávelA
fonte
A=$(echo "!!\\" | sed 's,\\,/,g');eval $A
não funciona quando o comando foi finalizado com uma barra invertida. Você é forçado a adicionar um espaço, por exemplo, aoC:\Foo\Bar\
else, como você disse, o shell aguardará a continuação da linha. Você também pode pressionar enter duas vezes. No primeiro caso, você obtémC:/Foo/Bar /
(com um espaço antes do/
; no segundo ele gera um erro. A função funciona bem.Eu não acho que você pode fazer isso. Você precisa copiar / colar novamente.
O problema não está relacionado à barra sendo também o separador de comando substituto, pois o comando substituto aceita qualquer separador. A questão é sobre as barras invertidas a serem substituídas, que já foram tratadas como simples escapamentos inúteis de caráter à sua direita.
Portanto, quando você chama o comando substitute, a barra invertida já desaparece da fonte. Apenas tente chamar novamente o comando como está (
!!
). Em vez de imprimir exatamente o mesmo comandoc:\foo
, ele executará o comando menos as barras invertidas já processadas que resultam emc:foo
.E, obviamente, você não pode encontrar nem substituir um personagem ausente. Tentar fazer isso disparará um erro.
fonte
echo c:\Foo
seguido por!!:gs,F,\\f,
. Mas Substituir a própria barra invertida parece ser uma dor.