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.


+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

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\\\"\""

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


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"'\'''

-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.


6
To nic nie dodaje do istniejących odpowiedzi.
jasonwryan
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.