Come sfuggire alle citazioni in shell?


66

Sto avendo problemi con la fuga di personaggi in Bash. Vorrei evitare virgolette singole e doppie durante l'esecuzione di un comando con un altro utente. Ai fini di questa domanda, diciamo che voglio ripetere quanto segue sullo schermo:

'single quote phrase' "double quote phrase"

Come posso evitare tutti i caratteri speciali, se devo anche passare a un altro utente:

sudo su USER -c "echo \"'single quote phrase' \"double quote phrase\"\""

Naturalmente, questo non produce il risultato giusto.


+1 per "Naturalmente, questo non produce i risultati giusti". bashè sulla buona strada per farmi arrabbiare.
Rolf

Risposte:


89

È possibile utilizzare la seguente sintassi letterale di stringa:

> echo $'\'single quote phrase\' "double quote phrase"'
'single quote phrase' "double quote phrase"

A partire dal man bash

Le parole del modulo $ 'stringa' sono trattate in modo speciale. La parola si espande in stringa, con i caratteri con escape backslash sostituiti come specificato dallo standard ANSI C. Le sequenze di escape barra rovesciata, se presenti, sono decodificate come 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
          \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)
          \cx    a control-x character

5
Eccessivo. Nella maggior parte dei casi non è necessario utilizzare la sintassi letterale di stringa.
fpmurphy,


12

In una shell POSIX, supponendo che nella stringa non vi siano variabili, comandi o espansioni della cronologia e non vi sia alcuna nuova riga, seguire queste prescrizioni di base:

  1. Per citare una stringa generica con virgolette singole, eseguire le seguenti azioni:

    1. Sostituisci qualsiasi sequenza di caratteri non a virgoletta singola con la stessa sequenza con virgolette singole iniziali e finali aggiunte: 'aaa' ==> ''aaa''

    2. Fuga con una barra rovesciata ogni carattere di virgoletta singola preesistente : ' ==> \'
      in particolare,''aaa'' ==> \''aaa'\'

  2. Per citare una stringa generica con virgolette doppie, eseguire le seguenti azioni:

    1. Aggiungi virgolette doppie iniziali e finali: aaa ==> "aaa"

    2. Scappa con una barra rovesciata ogni carattere di doppia virgoletta e ogni barra rovesciata: " ==> \", \ ==> \\

Un paio di esempi:

''aaa""bbb''ccc\\ddd''  ==>  \'\''aaa""bbb'\'\''ccc\\ddd'\'\'
                        ==>  "''aaa\"\"bbb''ccc\\\\ddd''"

in modo che l'esempio possa essere espanso con il seguente:

#!/bin/sh

echo \''aaa'\'' "bbb"'
echo "'aaa' \"bbb\""

sudo su enzotib -c 'echo \'\'\''aaa'\''\'\'\'' "bbb"'\'
sudo su enzotib -c 'echo "'\''aaa'\'' \"bbb\""'

sudo su enzotib -c "echo \\''aaa'\\'' \"bbb\"'"
sudo su enzotib -c "echo \"'aaa' \\\"bbb\\\"\""

10

Semplice esempio di virgolette di escape nella shell:

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

Viene fatto finendo uno già aperto ( '), posizionando uno sfuggito ( \'), quindi aprendo un altro ( ').

In alternativa:

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

Viene fatto finendo uno già aperto ( '), posizionando la citazione in un'altra citazione ( "'"), quindi aprendone un'altra ( ').

Correlati: Come evitare virgolette singole all'interno di stringhe tra virgolette singole? su stackoverflow SE


1

La risposta accettata funziona con una semplice citazione (a un livello):

$ echo $'\'single quote phrase\' "double quote phrase"'
'single quote phrase' "double quote phrase"

Per far funzionare il comando, è necessario citare due volte.
Questo script potrebbe fare tutto il lavoro:

#!/bin/bash

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

read -r line <<-\_line_to_quote_
'single quote phrase' "double quote phrase"
_line_to_quote_

quote "$line"; echo
quote "echo $(quote "$line")"; echo

Esegui lo script per ottenere:

$ script
''\''single quote phrase'\'' "double quote phrase"'
'echo '\'''\''\'\'''\''single quote phrase'\''\'\'''\'' "double quote phrase"'\'''

La prima riga funziona per un'eco semplice:

$ echo ''\''single quote phrase'\'' "double quote phrase"'
'single quote phrase' "double quote phrase"

La seconda riga funzionerà per il comando tra virgolette doppie:

sudo su USER -c 'echo '\'''\''\'\'''\''single quote phrase'\''\'\'''\'' "double quote phrase"'\'''

-3

echo 'I \' ma student 'non funziona. Ma i seguenti lavori:

echo $ 'I \' ma student 'Dalla pagina man di bash:

Tra virgolette singole non può verificarsi una virgoletta, anche se preceduta da una barra rovesciata. .... Le parole del modulo $ 'stringa' sono trattate in modo speciale. La parola si espande in stringa, con i caratteri con escape backslash sostituiti come specificato dallo standard ANSI C.


6
Questo non aggiunge nulla alle risposte esistenti.
Jasonwryan,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.