Escapando no bash

1

Dada uma mensagem de texto, eu preciso gerar programaticamente um comando bash para abrir o emulador de terminal e mostrar esse texto nele.
Por exemplo, para HelloWorld string de entrada, preciso retornar a seguinte sequência de saída:% gnome-terminal -e "$SHELL -c echo\ HelloWorld;exec\ $SHELL"

O problema é que minhas mensagens de entrada podem consistir em símbolos arbitrários.
Por tentativa e erro, verifiquei que diferentes símbolos precisam ter um número de vezes diferente:

"A" must be converted to "A"        (0 times to be escaped)
" " must be converted to "\ "       (1 times to be escaped)
"(" must be converted to "\\("     (2 times to be escaped)
"\" must be converted to "\\\\" (3 times to be escaped)

Por exemplo, \(o o)/ deve ser inserido no comando como \\\\\\(o\ o\\)\\/ : gnome-terminal -e "$SHELL -c echo\ \\\\\\(o\ o\\)\\/;exec\ $SHELL"

Na verdade, eu não sei nada sobre o bash, então não tenho total compreensão da lógica por trás disso.
Você poderia, por favor, me dizer a regra geral: como converter qualquer símbolo do subconjunto ASCII (10,32-126)?

Editar:
Para trazer mais clareza sobre o que estou fazendo.

Estou tentando escrever uma função (em alguma linguagem de programação) que recebe uma string InputText e retorna outra string, que é um comando bash correto.
Atualmente, estou tentando implementar essa função como simples concatenação de: 1) prefixo constante gnome-terminal -e "$SHELL -c echo
2) parte interna que depende do InputText
3) sufixo constante ;exec\ $SHELL"
O problema é com a parte interna. Estou tentando calculá-lo como concatenação do símbolo de cada InputText convertido. Mas eu não sei como converter um símbolo arbitrário.

Editar 2:
Graças à choroba pela idéia de usar aspas simples para evitar a fuga em massa.
Eu aprendi muito sobre bash. )

Esta é uma versão modificada da resposta da choroba.
A mesma ideia, mas sem "backslashies backslashes tandems", implementados em Lua:

function run_terminal(text)
   local function q(s) return "'"..s:gsub("'","'\''").."'" end
   os.execute(
      'gnome-terminal -e "$SHELL -c "'..q(q("echo "..q(text)..";exec $SHELL"))
   )
end
run_terminal "Some Text"

Editar 3:
Obrigado ao Gilles por mencionar a opção "-x COMMAND" do gnome-terminal. A citação não é necessária com esta opção, portanto, podemos reduzir o nível de cotação dentro dos comandos gerados:

function run_terminal(text)
   local function q(s) return "'"..s:gsub("'","'\''").."'" end
   os.execute("gnome-terminal -x sh -c "..q("echo "..q(text)..";exec $SHELL"))
end
run_terminal "Some Text"
    
por Egor Skriptunoff 04.04.2016 / 15:56

2 respostas

2

Cite a string e você só precisará inverter aspas. Se você citar duas vezes, você precisa escapar dos dois tipos de cotação.

Atualização: O terminal do Gnome precisa de uma cotação tripla. Apenas escape das aspas simples duas vezes na string e use aspas simples entre aspas na string inserida. Você precisa fazer backslash nas barras invertidas na string original também.

Prova: usei o seguinte script Perl:

#!/usr/bin/perl
use strict;
use warnings;
use feature qw{ say };

chomp( my $msg = <> );
$msg =~ s/\/\\/g;           # Quis backslashies backslashes tandem?
$msg =~ s/'/'\''/g for 1, 2;  # Replace ' by '\'' twice.
$msg =~ s/"/\"/g;             # Backslash double quotes.
system q(gnome-terminal -e 'bash -c "echo '\'') . $msg . q('\''; exec bash"');
    
por 04.04.2016 / 16:19
2

Esqueça citando e coloque o texto em uma variável de ambiente.

Use -x para iniciar um shell.

Não crie código para $SHELL : você não sabe qual é a sintaxe que ele entende. Execute o código em sh e chame $SHELL para invocar um shell interativo.

message='HelloWorld' gnome-terminal -x sh -c 'printf %s\n "$message"; unset message; exec "$SHELL"'
    
por 05.04.2016 / 02:42