Substitui a barra invertida por barra no último comando

10

Copiei o comando cd C:\foo\bar\ do PowerShell para o Cygwin e esperei que ele fosse executado. Agora estou tentando executar uma substituição para substituir todo o \ com / :

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

Não tenho certeza porque 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 de substituição"?

    
por Tanner Faulkner 22.12.2016 / 16:41

4 respostas

6

uma barra também é o delimitador do seu comando substituto, então você deve escapar como a string de substituição para não terminar a substituição antecipadamente

!!:gs/\/\//

ou mais claramente como sugerido nos comentários, usando algo além de barra como o delimitador

!!:gs|\|/|

Mas isso parece funcionar apenas em tcsh (o shell comumente designado onde estou), não consigo fazer o comando funcionar em bash , já que parece que escapar não funciona no primeiro argumento de :s

    
por 17.01.2017 / 22:00
4

Resposta curta: o fc comando de correção) do bash

fc é o comando, embutido no bash shell, feito para editar & re-execute comandos da história.
É presente no CygWin também e funciona em todas as distribuições do Linux nas quais eu testei:

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

Algumas explicações

  • fc é o bash integrado comando para listar ou editar e reexecutar comandos da lista de histórico.
  • -1 terá o último comando no histórico. Observe que mesmo !! é definido (lido em man bash ) como

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

  • -s para substituir um padrão por outro. Desta vez, a partir de help fc (comando interno, então help ):

    With the 'fc -s [pat=rep ...] [command]' format, COMMAND is re-executed after the substitution OLD=NEW is performed.

    Ok, eles significam pat=rep em vez de OLD=NEW ...

  • Os padrões serão lidos pelo shell, então temos que protegê-los com aspas: '\' e '/' .

Algumas palavras mais sobre por que você está recebendo "substituição falhou"

Parece que o modificador s não é (ainda ) implementou a substituição do caractere de barra invertida \ , que é o escape. Para ter certeza, deveríamos ver o código, por exemplo, da versão do gnu da expansão do histórico do bash (mas havia o comando acima para obter o que você estava tentando fazer ... então eu fico com preguiça ....).

Algumas notas:

  1. Somos levados a pensar que funcionará cada RegEx que encontramos trabalhando com sed , mas isso não é garantido. A barra invertida é o caracter de escape da expansão e o problema está aqui. Além disso, o comportamento da expansão está relacionado com as opções shopt , então devemos começar a ver caso por caso ...

  2. Quando você colar a string cd C:\Foo\Bar em seu shell bash, ela será expandida e aparecerá para o interpretador como cd C:FooBar ; desta forma, ele será armazenado na variável interna $_ também.
    Se você, em vez disso, colou cd "C:\Foo\Bar" ou cd 'C:\Foo\Bar' no $_ variável você deve encontrar C:\Foo\Bar .
    Como a expansão do Histórico é executada imediatamente após uma linha completa ser lida, antes que ela seja quebrada em palavras, você pode ficar tentado a usá-la com algum bashism mais ou menos simples, por exemplo, com alguns derivação de (talvez adicionando :p ou :q , "" , análise e assim por diante ...)

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

    Este é o momento para lembrar que não é seguro começar a jogar com o caminho e nomes de arquivo , especialmente se eles vierem do prancheta do Windows (leia, em geral, a página Por que não analisam ls ? , ele está essencialmente relacionado com a possibilidade de usar tabulação, espaços e novas linhas como caracteres corretos para os nomes dos arquivos e os diretórios ...).
    Além disso, quando você cola um texto capturado com o mouse , você também pode colar um espaço à esquerda. Isso pode evitar que seu comando termine no histórico (depende das opções do shell ...). Se assim for, seu seguinte !! será um comando não controlado ... (veja um exemplo em outra resposta ). Este é um risco tangível desnecessário .

Conclusão

History expansions introduce words from the history list into the input stream, making it easy to repeat commands, insert the arguments to a previous command into the current input line, or fix errors in previous commands quickly.

Se não for fácil, começo a pensar que estamos fazendo algo errado ;-)

Ad nauseam: uma pequena experiência

Eu habilitei histverify no shell ...

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

então eu pressiono Enter e como verificado expansão eu acho

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

então eu pressiono Enter novamente e ele ecoa

D:FooBar 1A 2A

Isto parece indicar que o substitution failed é gerado na expansão do histórico processado antes da expansão do Brace , então antes de tudo , e parece confirmar que o modificador s history não (ainda) processou a substituição do caractere \ como um regex real. .

    
por 23.01.2017 / 17:05
2

Você pode usar sed para substituir e executar o resultado.

Existem várias variantes possíveis para tal comando, mas no meu bash só este funcionou:

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

O \ é adicionado ao !! caso o último comando termine com um barra invertida. Sem ela, a concha ficará confusa e pedirá a continuação da linha.

Você também pode adicionar isso como uma função bash no arquivo ~/.bashrc :

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

Veja como isso funciona no meu Bash no Windows:

Para explicar como o comando A= atribui o valor correto à variável do shell A :

  • tail pega as últimas duas linhas do histórico de comandos, o que dá ao linhas de cd \mnt\c seguido por slash em si. A parte de history | tail -n 2 também pode ser escrita como history 2 .
  • head pega a primeira linha que é cd \mnt\c
  • cut corta o número da linha fornecido por history
  • sed substitui todos os anti-slashes por barras
  • eval executa o conteúdo da variável A
por 19.01.2017 / 22:20
-1

Eu não acho que você possa fazer isso. Você precisa copiar / passar novamente.

O problema não está relacionado à barra também o separador de comando substituto, já que o comando de substituição aceita qualquer separador. A questão é sobre as barras invertidas a serem substituídas, que já foram tratadas como simples escapes inúteis de caráter à sua direita.

Portanto, quando você chama o comando substituto, a barra invertida já desapareceu da origem. Apenas tente chamar novamente o comando como está ( !! ). Em vez de imprimir exatamente o mesmo comando, incluindo c:\foo , ele executará o comando menos as barras invertidas já processadas que resultam em c:foo .

E, obviamente, você não consegue encontrar nem substituir um personagem ausente. Tentar fazer isso irá disparar um erro.

    
por 17.01.2017 / 22:33