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