Jak uniknąć cytatów w skorupkach?

65

Mam problem z ucieczką postaci w bash. Chciałbym uciec od pojedynczych i podwójnych cudzysłowów podczas uruchamiania polecenia dla innego użytkownika. Na potrzeby tego pytania powiedzmy, że chcę powtórzyć następujące na ekranie:

'single quote phrase' "double quote phrase"

Jak mogę uciec od wszystkich znaków specjalnych, jeśli muszę również przejść do innego użytkownika:

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

Oczywiście nie daje to właściwego rezultatu.

m33lky
źródło
+1 dla „Oczywiście, że to nie daje właściwych wyników”. bashjest na dobrej drodze do doprowadzenia mnie do szaleństwa.
Rolf

Odpowiedzi:

88

Możesz użyć następującej składni literału łańcuchowego:

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

Od man bash

Słowa w postaci $ „string” są traktowane specjalnie. Słowo rozwija się do łańcucha znaków, a znaki specjalne z odwrotnym ukośnikiem są zastępowane zgodnie ze standardem ANSI C. Sekwencje specjalne odwrotnego ukośnika, jeśli są obecne, są dekodowane w następujący sposób:

          \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
SiegeX
źródło
5
Overkill. W większości przypadków nie trzeba używać składni literałowej.
fpmurphy
Więcej szczegółów tutaj stackoverflow.com/a/16605140/149221
mj41
12

W powłoce POSIX, zakładając, że w ciągu nie ma rozszerzenia zmiennej, polecenia ani historii i nie ma nowego wiersza, postępuj zgodnie z tymi podstawowymi zaleceniami:

  1. Aby zacytować ogólny ciąg z pojedynczymi cudzysłowami, wykonaj następujące czynności:

    1. Zastąp dowolną sekwencję znaków spoza pojedynczego cudzysłowu tą samą sekwencją dodanymi wiodącymi i końcowymi pojedynczymi cudzysłowami: 'aaa' ==> ''aaa''

    2. Ucieczka z ukośnikiem odwrotnym do każdego istniejącego pojedynczego cudzysłowu: ' ==> \'
      W szczególności''aaa'' ==> \''aaa'\'

  2. Aby zacytować ogólny ciąg z podwójnymi cudzysłowami, wykonaj następujące czynności:

    1. Dodaj wiodące i końcowe cudzysłowy: aaa ==> "aaa"

    2. Ucieczka odwrotnym ukośnikiem co znak podwójnego cudzysłowu i każdy znak odwrotnego ukośnika: " ==> \", \ ==> \\

Kilka przykładów:

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

tak, aby twój przykład mógł zostać rozszerzony o:

#!/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\\\"\""
enzotib
źródło
10

Prosty przykład ucieczki cytatów w powłoce:

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

Odbywa się to poprzez ukończenie już otwartej jednej ( '), umieszczenie klawisza Escape ( \'), a następnie otwarcie kolejnej ( ').

Alternatywnie:

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

Odbywa się to poprzez ukończenie już otwartego jednego ( '), umieszczenie cytatu w innym cytacie ( "'"), a następnie otwarcie kolejnego ( ').

Powiązane: Jak uniknąć pojedynczych cudzysłowów w ciągach pojedynczych? w stackoverflow SE

kenorb
źródło
1

Przyjęta odpowiedź działa na proste (jeden poziom) cytowanie:

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

Aby polecenie pojawiło się w działaniu, musisz zacytować dwa razy.
Ten skrypt może wykonać całą pracę:

#!/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

Uruchom skrypt, aby uzyskać:

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

Pierwszy wiersz działa na proste echo:

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

Drugi wiersz będzie działał dla polecenia podwójnego cudzysłowu:

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

źródło
-3

echo „Jestem studentem” nie działa. Ale następujące prace:

echo $ 'I \' ma student 'Ze strony podręcznika bash:

Pojedynczy cytat może nie wystąpić między pojedynczymi cudzysłowami, nawet jeśli poprzedzony jest odwrotnym ukośnikiem. .... Słowa w postaci $ „string” są traktowane specjalnie. Słowo rozwija się do łańcucha znaków, a znaki specjalne z odwrotnym ukośnikiem są zastępowane zgodnie ze standardem ANSI C.

Sarf
źródło
6
To nic nie dodaje do istniejących odpowiedzi.
jasonwryan