Pergunta

Vamos dizer, você tem um alias Bash como:

alias rxvt='urxvt'

que funciona bem.

No entanto:

alias rxvt='urxvt -fg '#111111' -bg '#111111''

não vai funcionar, e nem:

alias rxvt='urxvt -fg \'#111111\' -bg \'#111111\''

Assim como você acabar combinando-se abertura e fechamento aspas dentro de uma string depois de ter escapado citações?

alias rxvt='urxvt -fg'\''#111111'\'' -bg '\''#111111'\''

parece deselegante embora pudesse representar a mesma corda se você está permitido para concatenar-los assim.

Foi útil?

Solução

Se você realmente quiser usar aspas simples na camada mais externa, lembre-se que você pode colar os dois tipos de citação. Exemplo:

 alias rxvt='urxvt -fg '"'"'#111111'"'"' -bg '"'"'#111111'"'"
 #                     ^^^^^       ^^^^^     ^^^^^       ^^^^
 #                     12345       12345     12345       1234

Explicação de como '"'"' é interpretado como apenas ':

  1. ' End primeira citação que usa aspas simples.
  2. " Iniciar segunda citação, usando aspas.
  3. ' caráter Citado.
  4. segunda citação " End, usando aspas.
  5. ' Iniciar terceira cotação, usando aspas simples.

Se você não coloque espaços em branco entre (1) e (2), ou entre (4) e (5), o shell vai interpretar essa seqüência como uma palavra longa.

Outras dicas

Eu sempre basta substituir cada citação único incorporado com a seqüência: '\'' (isto é: Citação barra invertida quote quote) que fecha a corda, acrescenta uma cotação única escapou e reabre o string.


Muitas vezes eu chicotear acima de uma função "quotify" em meus scripts Perl para fazer isso por mim. Os passos seriam:

s/'/'\\''/g    # Handle each embedded quote
$_ = qq['$_']; # Surround result with single quotes.

Esta praticamente cuida de todos os casos.

A vida fica mais divertido quando você introduzir eval em seus shell-scripts. Você essencialmente tem que re-quotify tudo de novo!

Por exemplo, criar um script Perl chamado quotify contendo as afirmações acima:

#!/usr/bin/perl -pl
s/'/'\\''/g;
$_ = qq['$_'];

, em seguida, usá-lo para gerar uma seqüência corretamente citado:

$ quotify
urxvt -fg '#111111' -bg '#111111'

resultado:

'urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''

que pode então ser copy / colado no comando apelido:

alias rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''

(Se você precisa inserir o comando em um eval, execute o quotify novamente:

 $ quotify
 alias rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''

resultado:

'alias rxvt='\''urxvt -fg '\''\'\'''\''#111111'\''\'\'''\'' -bg '\''\'\'''\''#111111'\''\'\'''\'''\'''

que pode ser copiar / colar em um eval:

eval 'alias rxvt='\''urxvt -fg '\''\'\'''\''#111111'\''\'\'''\'' -bg '\''\'\'''\''#111111'\''\'\'''\'''\'''

Desde Bash 2,04 sintaxe $'string' (em vez de apenas 'string'; aviso: não confunda com $('string')) é um outro mecanismo que permite citando ANSI C-como sequências de escape e fazer a expansão única versão citada.

Um exemplo simples:

  $> echo $'aa\'bb'
  aa'bb

  $> alias myvar=$'aa\'bb'
  $> alias myvar
  alias myvar='aa'\''bb'

No seu caso:

$> alias rxvt=$'urxvt -fg \'#111111\' -bg \'#111111\''
$> alias rxvt
alias rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''

seqüências escapando comuns funciona como esperado:

\'     single quote
\"     double quote
\\     backslash
\n     new line
\t     horizontal tab
\r     carriage return

A seguir é cópia + colado documentação relacionada a partir man bash (versão 4.4):

As palavras do formulário $ 'string' são tratados especialmente. A palavra expande a corda, com caracteres escapou-barra invertida substituído conforme especificado pela norma ANSI C. sequências de escape de barra invertida, se presente, são descodificadas como se segue:

    \a     alert (bell)
    \b     backspace
    \e
    \E     an escape character
    \f     form feed
    \n     new line
    \r     carriage return
    \t     horizontal tab
    \v     vertical tab
    \\     backslash
    \'     single quote
    \"     double quote
    \?     question mark
    \nnn   the eight-bit character whose value is the octal 
           value nnn (one to three digits)
    \xHH   the eight-bit character whose value is the hexadecimal
           value HH (one or two hex digits)
    \uHHHH the Unicode (ISO/IEC 10646) character whose value is 
           the hexadecimal value HHHH (one to four hex digits)
    \UHHHHHHHH the Unicode (ISO/IEC 10646) character whose value 
               is the hexadecimal value HHHHHHHH (one to eight 
               hex digits)
    \cx    a control-x character

O resultado expandido é single-citado, como se o cifrão não estivesse presente.


Consulte Cotações e escapar: ANSI C como cordas em Bash-hackers. org wiki para mais detalhes. Também nota que "Festança alterações" arquivo ( visão geral aqui ) menciona um monte de mudanças e correções de bugs relacionados com o mecanismo de $'string' citando.

De acordo com unix.stackexchange.com como usar um caractere especial como um normal? ele deve funcionar (com algumas variações) em bash, zsh, mksh, ksh93 e FreeBSD e sh busybox.

Não vejo a entrada em seu blog (pls link?), Mas de acordo com o referência gnu :

encerrando caracteres entre aspas simples ( ‘'’) Preserva o valor de literal cada personagem dentro das aspas. UMA aspas simples não pode ocorrer entre aspas simples, mesmo quando precedidas por uma barra invertida.

para o bash não vai entender:

alias x='y \'z '

No entanto, você pode fazer isso se você cercar com aspas duplas:

alias x="echo \'y "
> x
> 'y

Eu posso confirmar que o uso '\'' para uma única citação dentro de uma string entre aspas simples não funciona em Bash, e pode ser explicada da mesma forma como o argumento de "colagem" de no início da rosca. Suponha que temos uma string: 'A '\''B'\'' C' (todas as citações aqui são aspas simples). Se ele é passado para echo, ele imprime o seguinte: A 'B' C. Em cada '\'' a primeira citação fecha a corrente do string entre aspas simples, a seguinte \' cola uma única citação para a cadeia anterior (\' é uma maneira de especificar uma única citação sem começar uma string), ea última citação abre outra única string.

Um exemplo simples de escapar citações no shell:

$ echo 'abc'\''abc'
abc'abc
$ echo "abc"\""abc"
abc"abc

É feito por terminar já abriu um ('), colocação escapou um (\'), em seguida, abrir outra ('). Esta sintaxe funciona para todos os comandos. É abordagem muito semelhante ao 1º resposta.

Ambas as versões estão trabalhando, seja com concatenação usando o caractere de aspas simples (\ ') escapou, ou com concatenação colocando o caractere de aspas simples dentro de aspas ( "').

O autor da pergunta não percebeu que havia uma cotação individual extra ( ') no final da sua última tentativa de escapar:

alias rxvt='urxvt -fg'\''#111111'\'' -bg '\''#111111'\''
           │         │┊┊|       │┊┊│     │┊┊│       │┊┊│
           └─STRING──┘┊┊└─STRIN─┘┊┊└─STR─┘┊┊└─STRIN─┘┊┊│
                      ┊┊         ┊┊       ┊┊         ┊┊│
                      ┊┊         ┊┊       ┊┊         ┊┊│
                      └┴─────────┴┴───┰───┴┴─────────┴┘│
                          All escaped single quotes    │
                                                       │
                                                       ?

Como você pode ver na peça agradável anterior de ASCII / arte Unicode, o último escapou aspas simples (\ ') é seguido por um aspas simples desnecessário ('). Usando uma sintaxe de marca-texto como o presente no Notepad ++ pode ser muito útil.

O mesmo é verdade para um outro exemplo como o seguinte:

alias rc='sed '"'"':a;N;$!ba;s/\n/, /g'"'"
alias rc='sed '\'':a;N;$!ba;s/\n/, /g'\'

Estes dois belos exemplos de aliases mostrar de uma forma muito intrincada e ofuscado como um arquivo pode ser alinhada para baixo. Ou seja, a partir de um arquivo com um monte de linhas você tem apenas uma linha com vírgulas e espaços entre os conteúdos das linhas anteriores. A fim de dar sentido ao comentário anterior, o seguinte é um exemplo:

$ cat Little_Commas.TXT
201737194
201802699
201835214

$ rc Little_Commas.TXT
201737194, 201802699, 201835214

Eu não estou especificamente abordar a questão citando porque, bem, às vezes, é apenas razoável considerar uma abordagem alternativa.

rxvt() { urxvt -fg "#${1:-000000}" -bg "#${2:-FFFFFF}"; }

que você pode então chamar como:

rxvt 123456 654321

A idéia é que você pode agora apelido isso sem preocupação com citações:

alias rxvt='rxvt 123456 654321'

ou, se você precisa incluir o # em todas as chamadas, por algum motivo:

rxvt() { urxvt -fg "${1:-#000000}" -bg "${2:-#FFFFFF}"; }

que você pode então chamar como:

rxvt '#123456' '#654321'

então, é claro, um alias é:

alias rxvt="rxvt '#123456' '#654321'"

(oops, eu acho que eu meio que fizemos o endereço citando:)

Eu só usar códigos shell .. por exemplo \x27 ou \\x22 como aplicável. Sem problemas, realmente,.

Uma vez que não se pode colocar aspas simples dentro de cadeias entre aspas simples, a opção mais simples e mais legível é usar uma string heredoc

command=$(cat <<'COMMAND'
urxvt -fg '#111111' -bg '#111111'
COMMAND
)

alias rxvt=$command

No código acima, o heredoc é enviado para o comando cat ea saída do que é atribuído a uma variável através do comando de substituição notação $(..)

Colocar uma única citação ao redor do heredoc é necessária, uma vez que está dentro de uma $()

IMHO a verdadeira resposta é que você não pode escapar aspas simples nas strings de aspas simples.

É impossível.

Se nós presumimos que estamos usando bash.

De manual de festa ...

Enclosing characters in single quotes preserves the literal value of each
character within the quotes.  A single quote may not occur
between single quotes, even when preceded by a backslash.

Você precisa usar um dos outros mecanismos de corda de fuga "ou \

Não há nada mágico sobre alias que exige que usar aspas simples.

Ambos os seguintes trabalhos em bash.

alias rxvt="urxvt -fg '#111111' -bg '#111111'"
alias rxvt=urxvt\ -fg\ \'#111111\'\ -bg\ \'#111111\'

Este último está usando \ escapar o caractere de espaço.

Também não há nada mágico sobre # 111111 que requer aspas simples.

As seguintes opções obtém o mesmo resultado as outras duas opções, em que o alias rxvt funciona como esperado.

alias rxvt='urxvt -fg "#111111" -bg "#111111"'
alias rxvt="urxvt -fg \"#111111\" -bg \"#111111\""

Você também pode escapar da incômoda # diretamente

alias rxvt="urxvt -fg \#111111 -bg \#111111"

A maioria destas respostas bateu sobre o caso específico que você está perguntando. Há uma abordagem geral que um amigo e tenho desenvolvido que permite arbitrária citando em caso de necessidade de citação do bash comandos através de várias camadas de expansão shell, por exemplo, através de ssh, su -c, bash -c, etc. Há um núcleo primitivo você precisa , aqui em bash nativa:

quote_args() {
    local sq="'"
    local dq='"'
    local space=""
    local arg
    for arg; do
        echo -n "$space'${arg//$sq/$sq$dq$sq$dq$sq}'"
        space=" "
    done
}

Este faz exatamente o que diz: que desembolsar-cita cada argumento individualmente (após a expansão bash, é claro):

$ quote_args foo bar
'foo' 'bar'
$ quote_args arg1 'arg2 arg2a' arg3
'arg1' 'arg2 arg2a' 'arg3'
$ quote_args dq'"'
'dq"'
$ quote_args dq'"' sq"'"
'dq"' 'sq'"'"''
$ quote_args "*"
'*'
$ quote_args /b*
'/bin' '/boot'

Ele faz a coisa óbvia para uma camada de expansão:

$ bash -c "$(quote_args echo a'"'b"'"c arg2)"
a"b'c arg2

(Note que as aspas em torno $(quote_args ...) são necessários para fazer o resultado em um único argumento para bash -c). E ele pode ser usado de forma mais geral para citar adequadamente através de várias camadas de expansão:

$ bash -c "$(quote_args bash -c "$(quote_args echo a'"'b"'"c arg2)")"
a"b'c arg2

O exemplo acima:

  1. shell-citações cada argumento para a quote_args interior individualmente e então combina a saída resultante em uma única discussão com as aspas internas.
  2. shell aspas bash, -c, eo resultado já uma vez citado a partir do passo 1, e em seguida, combina o resultado em uma única discussão com as aspas duplas exteriores.
  3. envia essa confusão como o argumento para o bash -c exterior.

Essa é a ideia em poucas palavras. Você pode fazer algumas coisas muito complicado com isso, mas você tem que ter cuidado com a ordem de avaliação e sobre o qual substrings são cotados. Por exemplo, o seguinte fazer as coisas erradas (por alguma definição de "errado"):

$ (cd /tmp; bash -c "$(quote_args cd /; pwd 1>&2)")
/tmp
$ (cd /tmp; bash -c "$(quote_args cd /; [ -e *sbin ] && echo success 1>&2 || echo failure 1>&2)")
failure

No primeiro exemplo, o bash expande imediatamente quote_args cd /; pwd 1>&2 em dois comandos separados, quote_args cd / e pwd 1>&2, de modo que o CWD ainda é /tmp quando o comando pwd é executado. O segundo exemplo ilustra um problema semelhante para englobamento. Na verdade, o mesmo problema básico ocorre com todas as expansões festança. O problema aqui é que uma substituição de comando não é uma chamada de função:. É, literalmente, avaliando um script bash e usando a sua saída como parte de outro script bash

Se você tentar simplesmente escapar dos operadores shell, você vai falhar, porque a cadeia resultante passado para bash -c é apenas uma seqüência de cordas individualmente citadas que não são então interpretadas como operadores, que é fácil de ver se você ecoar a corda que teria sido passado para bash:

$ (cd /tmp; echo "$(quote_args cd /\; pwd 1\>\&2)")
'cd' '/;' 'pwd' '1>&2'
$ (cd /tmp; echo "$(quote_args cd /\; \[ -e \*sbin \] \&\& echo success 1\>\&2 \|\| echo failure 1\>\&2)")
'cd' '/;' '[' '-e' '*sbin' ']' '&&' 'echo' 'success' '1>&2' '||' 'echo' 'failure' '1>&2'

O problema aqui é que você está over-citando. O que você precisa é para os operadores a não cotadas como entrada para o bash -c encerrando, o que significa que eles precisam estar fora da substituição de comando $(quote_args ...).

Por isso, o que você precisa fazer no sentido mais geral é que desembolsar-citar cada palavra do comando não se destina a ser expandido no momento da substituição de comando separadamente, e não aplicar qualquer extra de citar aos operadores shell:

$ (cd /tmp; echo "$(quote_args cd /); $(quote_args pwd) 1>&2")
'cd' '/'; 'pwd' 1>&2
$ (cd /tmp; bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")
/
$ (cd /tmp; echo "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")
'cd' '/'; [ -e *'sbin' ] && 'echo' 'success' 1>&2 || 'echo' 'failure' 1>&2
$ (cd /tmp; bash -c "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")
success

Uma vez feito isso, toda a cadeia é um jogo justo para posterior citando a níveis arbitrários de avaliação:

$ bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")"
/
$ bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")")"
/
$ bash -c "$(quote_args bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")")")"
/
$ bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")"
success
$ bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); [ -e *sbin ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")")"
success
$ bash -c "$(quote_args bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")")")"
success

etc.

Esses exemplos podem parecer exagerada, dado que palavras como success, sbin e pwd não precisa ser citada-shell, mas o ponto chave para lembrar ao escrever um script tomando entrada arbitrária é que você quer citar tudo o que você' re não absolutamente certo de não citando necessidade, porque você nunca sabe quando um usuário vai jogar em um Robert'; rm -rf /.

Para entender melhor o que está acontecendo nos bastidores, você pode brincar com duas funções auxiliares pequenas:

debug_args() {
    for (( I=1; $I <= $#; I++ )); do
        echo -n "$I:<${!I}> " 1>&2
    done
    echo 1>&2
}

debug_args_and_run() {
    debug_args "$@"
    "$@"
}

que irá enumerar cada argumento para um comando antes de executá-lo:

$ debug_args_and_run echo a'"'b"'"c arg2
1:<echo> 2:<a"b'c> 3:<arg2> 
a"b'c arg2

$ bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)"
1:<echo> 2:<a"b'c> 3:<arg2> 
a"b'c arg2

$ bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)")"
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'echo' 'a"b'"'"'c' 'arg2'> 
1:<echo> 2:<a"b'c> 3:<arg2> 
a"b'c arg2

$ bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)")")"
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'bash' '-c' ''"'"'debug_args_and_run'"'"' '"'"'echo'"'"' '"'"'a"b'"'"'"'"'"'"'"'"'c'"'"' '"'"'arg2'"'"''> 
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'echo' 'a"b'"'"'c' 'arg2'> 
1:<echo> 2:<a"b'c> 3:<arg2> 
a"b'c arg2

$ bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)")")")"
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'bash' '-c' ''"'"'debug_args_and_run'"'"' '"'"'bash'"'"' '"'"'-c'"'"' '"'"''"'"'"'"'"'"'"'"'debug_args_and_run'"'"'"'"'"'"'"'"' '"'"'"'"'"'"'"'"'echo'"'"'"'"'"'"'"'"' '"'"'"'"'"'"'"'"'a"b'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'c'"'"'"'"'"'"'"'"' '"'"'"'"'"'"'"'"'arg2'"'"'"'"'"'"'"'"''"'"''> 
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'bash' '-c' ''"'"'debug_args_and_run'"'"' '"'"'echo'"'"' '"'"'a"b'"'"'"'"'"'"'"'"'c'"'"' '"'"'arg2'"'"''> 
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'echo' 'a"b'"'"'c' 'arg2'> 
1:<echo> 2:<a"b'c> 3:<arg2> 
a"b'c arg2

No exemplo dado, simplesmente utilizado em vez de aspas plicas como mecanismo de escape exterior:

alias rxvt="urxvt -fg '#111111' -bg '#111111'"

Esta abordagem é adequada para muitos casos em que você só quer passar uma string fixa a um comando:. Basta verificar como o shell vai interpretar a string entre aspas por meio de um echo, e escapar caracteres com barra invertida, se necessário

No exemplo, veria que as aspas duplas são suficientes para proteger a string:

$ echo "urxvt -fg '#111111' -bg '#111111'"
urxvt -fg '#111111' -bg '#111111'

Aqui está uma elaboração sobre The One True Resposta mencionado acima:

Às vezes eu vou ser o download usando o rsync sobre ssh e tem que escapar um nome de arquivo com um 'nele duas vezes! (OMG!) Uma vez que para a festança e uma vez para ssh. O mesmo princípio de alternância de delimitadores de citação está no trabalho aqui.

Por exemplo, digamos que queremos chegar: Histórias LA de Louis Theroux ...

  1. Primeiro você coloque Louis Theroux entre aspas simples para bash e aspas duplas para ssh: 'Louis Theroux "'
  2. Em seguida, você usar aspas simples para escapar de uma aspas duplas '"'
  3. O uso de aspas duplas para escapar o apóstrofo "'"
  4. Em seguida, repita # 2, usando aspas simples para escapar de uma aspas duplas '"'
  5. Em seguida, coloque Stories LA em aspas simples para bash e aspas duplas para ssh: 'Histórias LA "'

E eis! Você acabar com esta:

rsync -ave ssh '"Louis Theroux"''"'"'"'"''"s LA Stories"'

que é uma enorme quantidade de trabalho para um pouco '- mas lá vai

Outra forma de corrigir o problema de muitas camadas de citação aninhada:

Você está tentando empinar demais para o espaço uma muito pequena, portanto, usar uma função bash.

O problema é que você está tentando ter muitos níveis de aninhamento, e a tecnologia básica alias não é poderoso o suficiente para acomodar. Use uma função do bash como este para torná-lo assim os, aspas duplas únicas cópias de carrapatos e passou em parâmetros são todos tratados normalmente como seria de esperar:

lets_do_some_stuff() {
    tmp=$1                       #keep a passed in parameter.
    run_your_program $@          #use all your passed parameters.
    echo -e '\n-------------'    #use your single quotes.
    echo `date`                  #use your back ticks.
    echo -e "\n-------------"    #use your double quotes.
}
alias foobarbaz=lets_do_some_stuff

Em seguida, você pode usar suas variáveis ??$ 1 e US $ 2 e, aspas simples e volta carrapatos sem se preocupar com a função apelido destruindo a sua integridade.

Este programa imprime:

el@defiant ~/code $ foobarbaz alien Dyson ring detected @grid 10385
alien Dyson ring detected @grid 10385
-------------
Mon Oct 26 20:30:14 EDT 2015
-------------
shell_escape () {
    printf '%s' "'${1//\'/\'\\\'\'}'"
}

Implementação explicação:

  • aspas duplas para que possamos aspas simples acondicionamento facilmente saída e usar o ${...} sintaxe

  • Pesquisa do bash e substituir se parece com: ${varname//search/replacement}

  • estamos substituindo ' com '\''

  • '\'' codifica um único ' assim:

    1. ' termina a única citando

    2. \' codifica uma ' (a barra invertida é necessária porque não estamos dentro de aspas)

    3. ' inicia única citando novamente

    4. festa concatena automaticamente seqüências sem espaço em branco entre

  • há uma \ antes de cada \ e ' porque essa é a regras de escape para ${...//.../...}.

string="That's "'#@$*&^`(@#'
echo "original: $string"
echo "encoded:  $(shell_escape "$string")"
echo "expanded: $(bash -c "echo $(shell_escape "$string")")"

P.S. Sempre codificar para cadeias entre aspas simples porque eles são muito mais simples do que cadeias entre aspas duplas.

Se você tem GNU Parallel instalado, você pode usar o seu interna citando:

$ parallel --shellquote
L's 12" record
<Ctrl-D>
'L'"'"'s 12" record'
$ echo 'L'"'"'s 12" record'
L's 12" record

A partir da versão 20190222 Você pode até --shellquote várias vezes:

$ parallel --shellquote --shellquote --shellquote
L's 12" record
<Ctrl-D>
'"'"'"'"'"'"'L'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'s 12" record'"'"'"'"'"'"'
$ eval eval echo '"'"'"'"'"'"'L'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'s 12" record'"'"'"'"'"'"'
L's 12" record

Ele vai citar a seqüência com conchas suportados (não só bash).

Esta função:

quote () 
{ 
    local quoted=${1//\'/\'\\\'\'};
    printf "'%s'" "$quoted"
}

permite citando de ' dentro '. Use como esta:

$ quote "urxvt -fg '#111111' -bg '#111111'"
'urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''

Se a linha a citação se torna mais complexa, como aspas duplas mistas com aspas simples, ele pode se tornar bastante complicado para obter a seqüência de citar dentro de uma variável. Quando tais casos aparecem, escreva a linha exata que você precisa para citar dentro de um roteiro (similar a este).

#!/bin/bash

quote ()
{
    local quoted=${1//\'/\'\\\'\'};
    printf "'%s'" "$quoted"
}

while read line; do
    quote "$line"
done <<-\_lines_to_quote_
urxvt -fg '#111111' -bg '#111111'
Louis Theroux's LA Stories
'single quote phrase' "double quote phrase"
_lines_to_quote_

saída:

'urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''
'Louis Theroux'\''s LA Stories'
''\''single quote phrase'\'' "double quote phrase"'

Todas as strings corretamente cotados dentro aspas simples.

Obviamente, seria mais fácil simplesmente para surround com aspas duplas, mas onde está o desafio nisso? Aqui está a resposta usando ofertas de preços apenas individuais. Eu estou usando uma variável em vez de alias de modo que é que é mais fácil para imprimir para a prova, mas é o mesmo que usar alias.

$ rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'
$ echo $rxvt
urxvt -fg '#111111' -bg '#111111'

Explicação

A chave é que você pode fechar o apóstrofo e reabri-lo quantas vezes quiser. Por exemplo foo='a''b' é o mesmo que foo='ab'. Então você pode fechar o apóstrofo, jogar em um apóstrofo \', em seguida, reabrir a próxima aspas simples.

Breakdown diagrama

Este diagrama deixa claro usando suportes para mostrar onde as aspas simples são abertas e fechadas. Aspas não são "encaixados" como parênteses pode ser. Você também pode pagar a atenção para o realce de cores, que seja correctamente aplicado. As cordas são mencionadas marrom, enquanto o \' é negro.

'urxvt -fg '\''#111111'\'' -bg '\''#111111'\'    # original
[^^^^^^^^^^] ^[^^^^^^^] ^[^^^^^] ^[^^^^^^^] ^    # show open/close quotes
 urxvt -fg   ' #111111  '  -bg   ' #111111  '    # literal characters remaining

(Esta é essencialmente a mesma resposta que Adrian, mas eu sinto isso explica-lo melhor. Também sua resposta tem 2 aspas simples supérfluos no final.)

Aqui está uma outra solução. Esta função terá um único argumento e apropriadamente citá-lo usando o caractere aspas simples, assim como a resposta votou acima explica:

single_quote() {
  local quoted="'"
  local i=0
  while [ $i -lt ${#1} ]; do
    local ch="${1:i:1}"
    if [[ "$ch" != "'" ]]; then
      quoted="$quoted$ch"
    else
      local single_quotes="'"
      local j=1
      while [ $j -lt ${#1} ] && [[ "${1:i+j:1}" == "'" ]]; do
        single_quotes="$single_quotes'"
        ((j++))
      done
      quoted="$quoted'\"$single_quotes\"'"
      ((i+=j-1))
    fi
    ((i++))
  done
  echo "$quoted'"
}

Assim, você pode usá-lo desta maneira:

single_quote "1 2 '3'"
'1 2 '"'"'3'"'"''

x="this text is quoted: 'hello'"
eval "echo $(single_quote "$x")"
this text is quoted: 'hello'

Se você está gerando a seqüência de shell dentro de Python 2 ou Python 3, podem ajudar a citar os argumentos:

#!/usr/bin/env python

from __future__ import print_function

try:  # py3
    from shlex import quote as shlex_quote
except ImportError:  # py2
    from pipes import quote as shlex_quote

s = """foo ain't "bad" so there!"""

print(s)
print(" ".join([shlex_quote(t) for t in s.split()]))

A saída será:

foo ain't "bad" so there!
foo 'ain'"'"'t' '"bad"' so 'there!'
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top