XXX 5.2. Escapament

En diem escapament al mecanisme de remarcar un caràcter prefixant-lo amb el caràcter \ per a indicar a la shell que interpreti el caràcter com el seu significat literal i no com un caràcter especial.

En alguns contextos (ex. amb les comandes echo i i sed), escapar un caràcter pot tenir l’efecte contrari. Podria indicar que es consideri un significat especial pel caràcter escapat.

Significats especials d’alguns caràcters

Quan escapem els següents caràcters amb les comandes echo i sed, són interpretats de la següent manera:

  • \n: nova línia

  • \r: retorn de línia

  • \t: tabulador

  • \v: tabulador vertical

  • \b: espai en rere

  • \a: alerta (en forma de so o parpadeig)

  • \0nn: tradueix a l’equivalent ASCII en octal. Equival a 0nn on nn és una cadena de dígits.

    Nota

    Es poden assignar caràcters ASCII a variables fent servir valors octals o hexadecimals escapats dins de $' ... '. Per exemple: cometadoble=$'\\042'.

  • \": Indica que les cometes s’interpretin com el caràcter i no com inici o final de text entre cometes.

    echo "Hola"                    # Sortida: Hola
    echo "\"Hola\" ... va dir."    # Sortida: "Hola" ... va dir.
    
  • \$: Indica que $ sigui interpretat com el caràcter. Així, les variables precedides per \$ no fan referència al seu valor.

    echo \$variable01             # Sortida: $variable01
    echo "El llibre val \$7.98."  # Sortida: El llibre val $7.98.
    
  • \\: Indica que la contrabarra sigui interpretada com el caràcter i no com escapament del següent caràcter.

    echo "\\"  # Sortida: \
    
    # Mentre que ...
    
    echo "\"   # Escapa la segona cometa doble.
               # Des de la línia de comandes invoca el *prompt* secundari
               # per continuar introduint una comanda multi-linia en
               # posteriors línies fins acabar amb ``"`` en aquest cas, o amb
               # ``ctrl-d`` en general.
               # Dins d'un guió, generaria un missatge d'error.
    
    # En canvi ...
    
    echo '\'   # Sortida: \
    

Exemple 1. Caràcters escapats

#!/bin/bash
# Demostració de caràcters escapats

### Comencem veient uns exemples bàsics d'escapament de caràcters

# Escapem un salt de línia

echo ""

echo "Aquest text es mostrarà
en dues línies."
# Sortida: Aquest text es mostrarà
#          en dues línies.

echo "Aquest text es mostrarà \
en una única línia."
# Sortida: Aquest text es mostrarà en una única línia.

echo; echo

echo "============="


echo "a\ve\vi\vo\vu"     # Sortida: a\ve\vi\vo\vu
# Amb l'opció -e, la comanda echo mostrarà els caràcters escapats.
echo "Tabulació vertical"
echo -e "a\ve\vi\vo\vu"   # Sortida:    a
                          #                 e
                          #                     i
                          #                         o
                          #                             u


echo "Cometes dobles"
echo -e "\042aeiou\042"       # Sortida: "aeiou"

# Amb $'\X' no cal l'opció -e

echo; echo "Salt de línia i (potser) PIIIP"
echo $'\n'           # Nova línia
echo $'\a'           # Alerta (PIIP).
# Depenent del terminal, pot no fer soroll sinó un parpadeig.

# Hem vist l'expansió $'\xxx'. Ara...

# La versió 2 de Bash va introduir l'expansió de cadenes de text $'\nnn'.
echo "Introducció de l'expansió de cadenes amb \$\' ... \' ..."
echo "... que inclou més marques de cometes."

echo $'a\t \042 \tz'   # Sortida: a    "   z
# Atenció: '\xxx' és un valor octal

# També funciona amb valors hexadecimals amb $'\xhhh'.
echo $'a\t \x22 \tz'  # Sortida: a    "   z

echo


# Assignació d'un caràcter ASCII a una variable.
cometes=$'\042'        # " ara $cometes val "
echo $cometes text entre cometes $cometes i fora de les cometes.

echo

# Concatenació de caràcters ASCII en una variable.
triple_subratllat=$'\137\137\137'  # 137 és el valor octal del caràcter ASCII _
echo "$triple_subratllat SUBRATLLAT $triple_subratllat"

echo

ABC=$'\101\102\103\010'      # 101, 102, 103 són els valors en octal dels caràcters A, B i C.
echo $ABC

echo

escape=$'\033'               # 033 és el valor octal pel caràcter d'escape (tecla ESC)
echo "\"escape\" mostrat com $escape"
# Sortida: "escape" mostrat com 
#                               ^ en el teu terminal segurament es mostra amb un
#                               símbol "raro"

echo

exit 0

Exemple 2. Detecció de tecles

A continuació un exemple més elaborat:

#!/bin/bash
# Demostració de captura de tecles
# Autor original: Sigurd Solaas, 20 abril 2011
# Per versió de Bash 4.2+.

key="De moment no has pres cap tecla"
while true; do
    clear
    echo "Demostració de tecles extra. Prova amb les tecles:"
    echo
    echo "* Insert, Delete, Home, End, Page_Up i Page_Down"
    echo "* Les quatre tecles del cursor"
    echo "* Tab, enter, esc i barra d'espai"
    echo "* Les tecles de lletres, nombres, etc."
    echo
    echo "    d = mostra la data i hora"
    echo "    q = surt"
    echo "================================"
    echo

    # Converteix la tecla separada home-key a home-key_num_7:
    if [ "$key" = $'\x1b\x4f\x48' ]; then
        key=$'\x1b\x5b\x31\x7e' #   expansió de text entre cometes
    fi

    # Converteix la tecla separada end-key a end-key_num_1.
    if [ "$key" = $'\x1b\x4f\x46' ]; then
        key=$'\x1b\x5b\x34\x7e'
    fi

    case "$key" in
        $'\x1b\x5b\x32\x7e')  # Insert
            echo Insert
            ;;
        $'\x1b\x5b\x33\x7e')  # Delete
            echo Delete
            ;;
        $'\x1b\x5b\x31\x7e')  # Home_key_num_7
            echo Inici
            ;;
        $'\x1b\x5b\x34\x7e')  # End_key_num_1
            echo Fi
            ;;
        $'\x1b\x5b\x35\x7e')  # Page_Up
            echo Pàgina amunt
            ;;
        $'\x1b\x5b\x36\x7e')  # Page_Down
            echo Pàgina abaix
            ;;
        $'\x1b\x5b\x41')  # Up_arrow
            echo Cursor amunt
            ;;
        $'\x1b\x5b\x42')  # Down_arrow
            echo Cursor abaix
            ;;
        $'\x1b\x5b\x43')  # Right_arrow
            echo Cursor dreta
            ;;
        $'\x1b\x5b\x44')  # Left_arrow
            echo Cursor esquerra
            ;;
        $'\x09')  # Tab
            echo Tab
            ;;
        $'\x0a')  # Enter
            echo Enter
            ;;
        $'\x1b')  # Escape
            echo Escape
            ;;
        $'\x20')  # Space
            echo Space
            ;;
        d)
            date
            ;;
        q)
            echo "Això s'acaba..."
            echo
            exit 0
            ;;
        *)
            echo Has pres: \'"$key"\'
            ;;
    esac

    echo
    echo "================================"

    unset K1 K2 K3
    read -s -N1 -p "Prem una tecla: "
    K1="$REPLY"
    read -s -N2 -t 0.001
    K2="$REPLY"
    read -s -N1 -t 0.001
    K3="$REPLY"
    key="$K1$K2$K3"

done

exit $?

Exemple 3. Expansió de cadenes de text

Considera també el següent exemple que també apareix a XXX 37.1. Bash, version 2.

#!/bin/bash

# XXX Demostració d'expansió de cadenes de text
# Introduced with version 2 of Bash.

#  Strings of the form $'xxx'
#+ have the standard escaped characters interpreted.

echo $'Ringing bell 3 times \a \a \a'
# May only ring once with certain terminals.
# Or ...
# May not ring at all, depending on terminal settings.
echo $'Three form feeds \f \f \f'
echo $'10 newlines \n\n\n\n\n\n\n\n\n\n'
echo $'\102\141\163\150'
#   B   a   s   h
# Octal equivalent of characters.

exit

Exemple 4. Comportament de \

El comportament de \ depén de si apareix:

# XXX Demostració del comportament de \

                      #  Simple escaping and quoting
echo \z               #  z
echo \\z              # \z
echo '\z'             # \z
echo '\\z'            # \\z
echo "\z"             # \z
echo "\\z"            # \z

                      #  Command substitution
echo `echo \z`        #  z
echo `echo \\z`       #  z
echo `echo \\\z`      # \z
echo `echo \\\\z`     # \z
echo `echo \\\\\\z`   # \z
echo `echo \\\\\\\z`  # \\z
echo `echo "\z"`      # \z
echo `echo "\\z"`     # \z

                      # Here document
cat <<EOF              
\z                      
EOF                   # \z

cat <<EOF              
\\z                     
EOF                   # \z

# These examples supplied by Stéphane Chazelas.

Exemple 5. Contrabarra com a valor d’una variable

Els elements d’una cadena de caràcters assignada a una variable poden ser escapats, però el caràcter d’escapament en si (la contrabarra) no pot ser assignada com a únic valor a una variable.

# XXX Demostració de \ com a valor de variable

variable=\
echo "$variable"
# Will not work - gives an error message:
# test.sh: : command not found
# A "naked" escape cannot safely be assigned to a variable.
#
#  What actually happens here is that the "\" escapes the newline and
#+ the effect is        variable=echo "$variable"
#+                      invalid variable assignment

variable=\
23skidoo
echo "$variable"        #  23skidoo
                        #  This works, since the second line
                        #+ is a valid variable assignment.

variable=\ 
#        \^    escape followed by space
echo "$variable"        # space

variable=\\
echo "$variable"        # \

variable=\\\
echo "$variable"
# Will not work - gives an error message:
# test.sh: \: command not found
#
#  First escape escapes second one, but the third one is left "naked",
#+ with same result as first instance, above.

variable=\\\\
echo "$variable"        # \\
                        # Second and fourth escapes escaped.
                        # This is o.k.

Exemple 6. Escapament d’espai

Quan escapem espais, hem de tenir present que té implicacions a l’hora de separar paraules en una llista d’arguments.

# XXX Demostració d'escapament d'espais en blanc

file_list="/bin/cat /bin/gzip /bin/more /usr/bin/less /usr/bin/emacs-20.7"
# List of files as argument(s) to a command.

# Add two files to the list, and list all.
ls -l /usr/X11R6/bin/xsetroot /sbin/dump $file_list

echo "-------------------------------------------------------------------------"

# What happens if we escape a couple of spaces?
ls -l /usr/X11R6/bin/xsetroot\ /sbin/dump\ $file_list
# Error: the first three files concatenated into a single argument to 'ls -l'
#        because the two escaped spaces prevent argument (word) splitting.

Exemple 7. Escapament i comandes multi-línia

Amb \ també disposem d’un mecanisme per escriure comandes multi-línia. Ja ho hem vist per sobre, a un exemple previ. Considera aquest exemple més complet:

# XXX Demostració d'ús de \ per construir comandes en més d'una línia

(cd /source/directory && tar cf - . )\
    (cd /dest/directory && tar xpvf -)
# Repeating Alan Cox's directory tree copy command,
# but split into two lines for increased legibility.

# As an alternative:
tar cf - -C /source/directory .
tar xpvf - -C /dest/directory
# See note below.
# (Thanks, Stéphane Chazelas.)

Nota

En cas que la línia acabi amb el caràcter | (pipe), no és extrictament necessari escapar el salt de línia. Amb tot, es considera una bona pràctica escapar sempre el final de cada línia que continua amb la següent.

Exemple 8. Comandes multi-línia i text

# XXX Demostració de text en més d'una línia

echo "foo
bar"
#foo
#bar

echo

echo 'foo
bar'    # No difference yet.
#foo
#bar

echo

echo foo\
    bar     # Newline escaped.
#foobar

echo

echo "foo\
    bar"     # Same here, as \ still interpreted as escape within weak quotes.
#foobar

echo

echo 'foo\
    bar'     # Escape character \ taken literally because of strong quoting.
#foo\
    #bar

# Examples suggested by Stéphane Chazelas.