shell

Wyeskejpuj apostrofa na fest !

Posted by Maciej Suszko on April 21, 2012
Uncategorized / No Comments

Tym razem dosyć banalny problem – jak wyeskejpować znak apostrofu w shellu… No niby prosta sprawa, podobnie jak każdy inny znak – poprzedzając go znakiem odwrotnego ukośnika, czyli tzw. backslashem. Ale czy na pewno?

W poniższych przykładach będą używane bash(1) i tcsh(1):

tlhscd@ibox:~ $ bash --version
GNU bash, version 4.2.20(0)-release (amd64-portbld-freebsd9.0)
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

tlhscd@ibox:~ $ csh --version
tcsh 6.18.01 (Astron) 2012-02-14 (x86_64-amd-FreeBSD) options wide,nls,dl,al,kan,
sm,rh,color,filec
tlhscd@ibox [tcsh]:~ $ echo jakis 'string $nowy_string'
jakis string $nowy_string

tlhscd@ibox [tcsh]:~ $ echo jakis \'string $nowy_string\'
nowy_string: Undefined variable.

tlhscd@ibox [tcsh]:~ $ echo jakis \'string \$nowy_string\'
jakis 'string $nowy_string'

W pierwszym przypadku do komendy echo zostały przekazane dwa argumenty – jakis i ‘string $nowy_string‘, w drugim trzy – jakis, ‘string oraz $nowy_string’.  W tym przypadku $nowy_string’ potraktowany został przez powłokę jako nazwa niezdefinowanej zmiennej. Musimy wyeskejpować znak dolara, żeby osiągnąć zamierzony cel – w powłoce Bourne-Again SHell będzie podobnie, z tą różnicą że nie dostaniemy informacji o niezdefiniowanej zmiennej:

tlhscd@ibox [bash]:~ $ echo jakis 'string $nowy_string'
jakis string $nowy_string

tlhscd@ibox [bash]:~ $ echo jakis \'string $nowy_string\'
jakis 'string '

tlhscd@ibox [bash]:~ $ echo jakis \'string \$nowy_string\'
jakis 'string $nowy_string'

Na pewno ktoś powie, że zamiast eskejpować apostrofy, można do echo przekazać jeden argument w takiej postaci (mając na uwadze to, że $nowy_string będzie traktowany jako zmienna):

tlhscd@ibox [tcsh]:~ $ echo "jakis 'string \$nowy_string'"
nowy_string: Undefined variable.

tlhscd@ibox [bash]:~ $ echo "jakis 'string \$nowy_string'"
jakis 'string $nowy_string'

Rozwiązaniem będzie przekazanie do echo jednego argumentu zawartego między apostrofami:

tlhscd@ibox [tcsh]:~ $ echo 'jakis '\''string $nowy_string'\'
jakis 'string $nowy_string'

tlhscd@ibox [bash]:~ $ echo 'jakis '\''string $nowy_string'\'
jakis 'string $nowy_string'

Powyższe stanie się bardziej czytelne, jeżeli robzbijemy argument na poszczególne składowe:

tlhscd@ibox [tcsh]:~ $ echo 'jakis '   \'   'string $nowy_string'   \'
jakis ' string $nowy_string '

A teraz przykład, który skłonił mnie do napisania tego własnie artykułu – alias w powłoce csh, którego argumentem jest ścieżka do pliku *.rar chronionego hasłem ‘[ha$lo]’ używany do wypakowania zawartości:

tlhscd@ibox [tcsh]:~ $ alias prar 'rar x -p'\''[ha$lo]'\'' -o+ \!:1'

tlhscd@ibox [tcsh]:~ $ prar plik.rar 

RAR 4.11   Copyright (c) 1993-2012 Alexander Roshal   17 Feb 2012
Shareware version         Type RAR -? for help

Extracting from plik.rar

Extracting  plik.txt                                                  OK
All OK

Tags: , ,