Portál AbcLinuxu, 2. května 2025 05:48

Odstraňujeme bashismy

16. 2. 2011 | David Watzke
Články - Odstraňujeme bashismy  

Občas když lidé píší shellové skripty, používají obraty z Bashe, aniž by si to uvědomovali. Někdy je pro změnu používají vědomě tam, kde je to zbytečné. V tomto článku si ukážeme několik příkazů z Bashe, jimž je třeba se vyhnout, chceme-li kompatibilitu, například s Dash.

Má-li skript fungující v Bashi hashbang "#!/bin/sh", mělo by to znamenat, že jej lze spustit i pomocí Bourne shellu, dash a ksh. Pokud tomu tak není, je vhodné jej změnit na "#!/bin/bash" nebo jej přepsat. Jak se rozhodnout?

Motivace pro přepis

Jak už zde zaznělo, silným argumentem pro používání standardní syntaxe Bourne shellu (a kompatibilních shellů, jako je dash či ksh) je zpětná kompatibilita, která ovšem souvisí i s externími nástroji, které ze skriptu voláte. Dalším kladem je (v některých případech) rychlost vykonávání, která je zpravidla u jednodušších shellů vyšší. Jiný argument pro je ten, že menší shell je vhodnější pro nasazení na mobilní či embedded zařízení s omezenými zdroji (málo paměti, pomalý procesor).

Kdy se to nevyplatí

Pokud pro vás ovšem zmíněné vlastnosti nejsou důležité, pak asi neexistuje pádný důvod se nějak omezovat. Například skript pro převod videa zaprvé nebude mít pravděpodobně tak dlouhou životnost, aby bylo nutné si nějak zvlášť lámat hlavu s kompatibilitou a co se týče embedded zařízení, tak pro ty takový skript z principu není určený. Pokud vás zaujala zpětná kompatibilita, je třeba si uvědomit, že ta souvisí i s používáním kompatibilních externích nástrojů – budete-li například v shellovém skriptu používat rozšíření nástrojů GNU (oproti standardu), tak to poněkud postrádá smysl. V každém případě je třeba nejprve se rozhodnout, zda přepis nebude jen ztrátou času.

Konkrétní nekompatibilní příkazy

Lidé v Bashi často nahrazují příkaz test voláním [[, které je (dle mého zkoumání) z nějakého důvodu rychlejší než [. Toto je ovšem nekompatibilní. Zrovna tak není možné používat "(( ))" nebo "$[ ]". Ovšem "$(( ))" funguje, i když oproti Bashi omezeně. Ukázka v Bashi:

#!/bin/bash

x=0
((x++))
x=$[x+1]

if((x==2)); then
	echo "V pořádku..."
fi

file="/tmp/testfile"

[[ ! -e "$file" ]] && echo "$file neexistuje"

Kdyby tento skript dával smysl a vyplatilo se nám ho přepisovat, přepis by vypadal takto:

#!/bin/sh

x=0
: $(( x+=2 ))

if [ "$x" -eq 2 ]; then
	echo "V pořádku..."
fi

file="/tmp/testfile"

[ ! -e "$file" ] && echo "$file neexistuje"

Test "[" je v klasickém shellu omezený oproti Bashi, například pro porovnání dvou řetězců nepoužívá operátor "==", ale "=". Někdy se v Bashi můžete setkat s přesměrováním "<<<", které přesměruje zadaný řetězec na standardní vstup programu. Na takové vychytávky zapomeňte, místo toho je třeba použít například echo či printf a příkaz dát za rouru:

# bash
[ "$1" == "$2" ] && tr -d 'x' <<< "xxaxxhxxoxxjx"

# sh
[ "$1" = "$2" ] && echo "xxaxxhxxoxxjx" | tr -d 'x'

Podstatná věc, na kterou v sh můžete zapomenout, jsou pole. Je to jedna z věcí, která může zkomplikovat přepis skriptu. Bash má také více vestavěných funkcí a klíčových slov: v sh neexistuje declare, disown, shopt, time, select a function či let. Některé vestavěné funkce, které má sh společné s Bashem, jsou ochuzené o různé přepínače či funcionalitu, například echo nemá přepínač -e a read vyžaduje název proměnné.

Zrovna tak není možné přesměrovat standardní vstup i výstup najednou pomocí &> soubor, ale je třeba použít > soubor 2>&1.

### Bash

function f {
	echo -e "\n\nTest" >&2
	read
	echo ${REPLY:-nic...}
}

f &> out

### sh

f() {
	printf "\n\nTest\n" >&2
	read REPLY
	echo ${REPLY:-nic...}
}

f > out 2>&1

Pochopitelně nefungují ani věci jako PATH+=":~/bin" nebo ${!BASH*}. Místo {1..10} je potřeba použít $(seq 1 10) a $UID je nutné nahradit za $(id -ru). V sh také není source, místo toho lze použít jednoduše . (tečku).

### Bash

source /etc/profile
PATH+="~/bin"
uid="$UID"

### sh

. /etc/profile
PATH="$PATH:$HOME/bin"     # sh neprovádí expanzi "~" v PATH
uid="$(id -ru)"

Tolik tedy k základním věcem, na které je třeba dát si pozor. Na anglické Ubuntu wiki se tímto tématem zabývají také, viz Dash as /bin/sh. Pochopitelně, pokud chcete mít jistotu, že je skript kompatibilní se sh, tak není nic jednoduššího, než jej spustit např. pomocí dash.

Skript checkbashisms

Vývojáři Debianu v polovině roku 2010 odstraňovali použití Bashe ze sestavovacích skriptů a při té příležitosti napsali v Perlu program checkbashisms, který se snaží detekovat některé "bashismy", což je označení pro nekompatibilní rozšíření Bashe. V některých případech rovnou vypisuje i náznak triviálního řešení.

possible bashism in /tmp/ncoda line 235 (alternative test command ([[ foo ]] should be [ foo ])):
                if [[ "$oformat" == "wav" ]]; then
possible bashism in /tmp/ncoda line 235 (should be 'b = a'):
                if [[ "$oformat" == "wav" ]]; then
possible bashism in /tmp/ncoda line 253 (<<< here string):
        oformat="$(tr '[[:upper:]]' '[[:lower:]]' <<< "$oformat")"
possible bashism in /tmp/ncoda line 368 (declare):
        declare option_${OPTION}=true
possible bashism in /tmp/ncoda line 385 ('((' should be '$(('):
  if (( $# == 0 )); then

V tomto výpisu je pět řádků, které by bylo třeba upravit, aby bylo korektní použít hashbang #!/bin/sh. Každý z těchto konkrétních případů jsem popsal v článku.

Další články z této rubriky

VDR a DVB-T2, část 2.
VDR a DVB-T2, část 1.
Šifrovaný Proxmox VE 6: ZFS, LUKS, systemd_boot a Dropbear
MapTiler – proměňte obrázek v zoomovatelnou mapu
Syncthing

Diskuse k tomuto článku

16.2.2011 02:33 Jirka P
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Odpovědět | Sbalit | Link | Blokovat | Admin
Kanonický způsob, jak přepsat

((x++));

do POSIXu, je toto:

: $(( x+=1 ));

což má výhodu, že jméno proměnné píšete jen jednou.

Řetězec na vstup dostanete taky here-docem (výhoda: dá se použít i pro jiné deskriptory než 0):

command <<E1 3<<E2
... tohle jde na fd 0
E1
... a tohle na 3
E2
16.2.2011 08:32 Martin Povolný | blog: Krev na widlich | Brno
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Ono to chce dat pozor, abyste s vanickou nevylil i dite.

Je jiste chvalyhodne, ze distribuce nahrazuji volani bash pomoci sh v jednoduchych skriptech o par radcich, kterych se pousti dvouciferne cislo po sobe, ruzne se volaji navzajem apod. Tam dosahnete zrychleni startu prostredi.

Ale pokud mam slozitejsi skript, tak zrovna [[ expr ]] urcite nechci nahrazovat, protoze [[ expr ]] je build-in a [ expr ] mi forkne dalsi proces. Proto je taky [[ rychlejsi..

Takze pokud pisete startovaci skripty pro distribuci, tak fajn, ma cenu se vyhnout "bashismum", ale pokud pisete nejakou aplikaci, ktera bezi na PC nad linuxem a shodou okolnosti mate kus v shellu, tak muze byt naopak zadouci vychytavky, ktere bash nabizi maximalne vyuzit.
16.2.2011 10:54 CET
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Zrovna jsem na to taky nedavno koukal. [[ je uvaden jako Compound Command, kdezto "test" a "[" je uvaden mezi builtin commands. Vyhoda pouziti "test" a "[" je tedy, ze funguje vzdy - bud primo podporovana shellem (bashem) nebo existuji externi utility z coreutils. test nebo [ tedy IMHO neforkne proces, pokud je to interni prikaz shellu (napr. bashe), takze je taky rychly.

Pokud uz clovek potrebuje, aby neco bezelo opravdu rychle, tak je asi lepsi pouzit nejaky jiny jazyk (perl, php, python), ktery nejdriv kod zkompiluje nebo jinak pripravi a pak uz bezi plnou rychlosti, nez to mastit v shellu, protoze tam bude zapotrebi urcite take spousta dalsich externich utilit (ed, sed, awk, sort, uniq, cut, wc...) a pak uz bude jedno, jestli se [[ vykona o trosinku rychlejc nez [.
16.2.2011 11:12 Michal Kubeček | skóre: 72 | Luštěnice
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Ale pokud mam slozitejsi skript, tak zrovna [[ expr ]] urcite nechci nahrazovat, protoze [[ expr ]] je build-in a [ expr ] mi forkne dalsi proces. Proto je taky [[ rychlejsi..

V bashi jsou i test a [ builtin. Smysl [[ ... ]] vidím jen v tom, že má navíc operátor =~ (matchování regulárních výrazů) a že =, == a != matchují podle wildcards. Což ale může být dost matoucí, protože jsem přesvědčen, že nemalá část těch, kdo [[ ... ]] používají, tohle neví a myslí si, že porovnávají na rovnost.

16.2.2011 13:20 Jirka P
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Ještě navíc [[ nedělá word-splitting na svůj vnitřek.
16.2.2011 13:23 Jirka P
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
[ expr ] mi forkne dalsi proces
Opravdu? Najděte mi tedy ten fork:
jirka@debian:/tmp$ strace sh -c '[ 0 = 0 ]'
execve("/bin/sh", ["sh", "-c", "[ 0 = 0 ]"], [/* 46 vars */]) = 0
brk(0)                                  = 0x805f000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb785d000
access("/etc/ld.so.preload", R_OK)      = 0
open("/etc/ld.so.preload", O_RDONLY)    = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=35, ...}) = 0
mmap2(NULL, 35, PROT_READ|PROT_WRITE, MAP_PRIVATE, 3, 0) = 0xb785c000
close(3)                                = 0
munmap(0xb785c000, 35)                  = 0
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=140547, ...}) = 0
mmap2(NULL, 140547, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb783a000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/i686/cmov/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\320m\1\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1323460, ...}) = 0
mmap2(NULL, 1333608, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb76f4000
mmap2(0xb7834000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x13f) = 0xb7834000
mmap2(0xb7837000, 10600, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7837000
close(3)                                = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb76f3000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb76f38d0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0xb7834000, 8192, PROT_READ)   = 0
mprotect(0xb787b000, 4096, PROT_READ)   = 0
munmap(0xb783a000, 140547)              = 0
getpid()                                = 20048
rt_sigaction(SIGCHLD, {SIG_DFL, [CHLD], SA_RESTART}, {SIG_DFL, [], 0}, 8) = 0
geteuid32()                             = 1000
brk(0)                                  = 0x805f000
brk(0x8080000)                          = 0x8080000
getppid()                               = 20047
stat64("/tmp", {st_mode=S_IFDIR|S_ISVTX|0777, st_size=16384, ...}) = 0
stat64(".", {st_mode=S_IFDIR|S_ISVTX|0777, st_size=16384, ...}) = 0
rt_sigaction(SIGINT, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGINT, {0x8056520, ~[RTMIN RT_1], 0}, NULL, 8) = 0
rt_sigaction(SIGQUIT, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGQUIT, {SIG_DFL, ~[RTMIN RT_1], 0}, NULL, 8) = 0
rt_sigaction(SIGTERM, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGTERM, {SIG_DFL, ~[RTMIN RT_1], 0}, NULL, 8) = 0
exit_group(0)                           = ?
Tohle je dash, ale v bashi je to podobný, jen delší.
progdan avatar 16.2.2011 08:37 progdan | skóre: 34 | blog: Archař | Teplice/Brno
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Odpovědět | Sbalit | Link | Blokovat | Admin
Zajimavy clanek, asi si zacnu davat vetsi pozor, jestli psat #!/bin/sh nebo #!/bin/bash...

PS: vypadnul vam odkaz na tu ubuntu wiki ;)
Collecting data is only the first step toward wisdom, but sharing data is the first step toward the community.
16.2.2011 09:46 merlyn
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
a pritom bys mel psat #!/usr/bin/env bash
Jardík avatar 16.2.2011 16:26 Jardík | skóre: 40 | blog: jarda_bloguje
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
To si pomůžeš. Z hardkódovanýho /bin/bash na hardkódovaný /usr/bin/env.
Věřím v jednoho Boha.
16.2.2011 17:55 Lukáš Zapletal | skóre: 42 | blog: lzapův svět | Olomouc
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Jak kde...
pavlix avatar 16.2.2011 19:50 pavlix | skóre: 54 | blog: pavlix
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
a pritom bys mel psat #!/usr/bin/env bash
Jako aby mi ty skripty nefungovaly při startu systému, pokud mám /usr na samostatném oddílu, jo?
Já už tu vlastně ani nejsem. Abclinuxu umřelo.
Jardík avatar 16.2.2011 20:12 Jardík | skóre: 40 | blog: jarda_bloguje
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Né, ale kdybys měl bash třeba v /opt/bash/bin/ a né v /bin/
Věřím v jednoho Boha.
pavlix avatar 16.2.2011 21:03 pavlix | skóre: 54 | blog: pavlix
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
To mi bude při odpojeném /usr hodně platné.
Já už tu vlastně ani nejsem. Abclinuxu umřelo.
Jardík avatar 16.2.2011 21:21 Jardík | skóre: 40 | blog: jarda_bloguje
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Co až budete mít na samostatném oddíle /bin, /lib a /etc ...
Věřím v jednoho Boha.
pavlix avatar 17.2.2011 00:47 pavlix | skóre: 54 | blog: pavlix
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Pak ti nenaběhne /sbin/init (minimálně na Fedoře), a jádro ti řekne, že seš kenelovej panic a administrátor na nic.
Já už tu vlastně ani nejsem. Abclinuxu umřelo.
Jardík avatar 17.2.2011 01:10 Jardík | skóre: 40 | blog: jarda_bloguje
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
/sbin/init narvu do initrd
Věřím v jednoho Boha.
pavlix avatar 17.2.2011 02:05 pavlix | skóre: 54 | blog: pavlix
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Narvi si ho kam chceš, klidně s celým systémem :).
Já už tu vlastně ani nejsem. Abclinuxu umřelo.
17.2.2011 12:56 snehuliak
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
> Zajimavy clanek, asi si zacnu davat vetsi pozor, jestli psat #!/bin/sh nebo #!/bin/bash...

#!/bin/sh Zavisi od distribucie. Napriklad v Ubuntu to znamena dash (co tie nie je sh) a vo Fedore #!/bin/sh znamena bash...

Ak chce niekto pisat script pre #!/bin/sh mal by ho pisat naozaj pre #!/bin/sh inak mu to nemusi inde fungovat.

Tiez neviem preco distribucie "zahmlievaju" skutocny shell - specialne v startup scriptoch. Ked je to raz dash tak nech maju v startup scriptoch #!/bin/dash a ked ficia na bash tak nech tam maju #!/bin/bash. Skratka je v tom trochu zmatok...
17.2.2011 23:34 imploder | skóre: 11
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
+1
17.2.2011 23:35 imploder | skóre: 11
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Ale /bin/sh by měl být shell kompatibilní s Bourne shellem (původním "sh") - aspoň myslím.
22.2.2011 01:33 Sten
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
/bin/sh musí být kompatibilní s POSIX shellem. Nicméně POSIX shell je kompatibilní s původním Bourne shellem, ale má pár ne moc používaných věcí navíc (třeba komentáře).
22.2.2011 18:07 Ash | skóre: 53
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
...a funguje tam spousta Bashismů a tak :D
16.2.2011 08:57 Jan Kurik | blog: Hemis
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Odpovědět | Sbalit | Link | Blokovat | Admin
Jen bych podotknul, že spousta z těch tak zvaných "bashismu" nepochází z shellu bash, ale byly už o něco dříve implementovány v ksh (možná i jinde, jiné shelly moc neznám), odkud je bash převzal.
16.2.2011 09:12 dTTb
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Odpovědět | Sbalit | Link | Blokovat | Admin
Zrovna tak není možné přesměrovat standardní vstup i výstup...
nema tam byt standartni i chybovy vystup?
David Watzke avatar 16.2.2011 09:55 David Watzke | skóre: 74 | blog: Blog... | Praha
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Ano, díky.
“Being honest may not get you a lot of friends but it’ll always get you the right ones” ―John Lennon
16.2.2011 11:23 w4rr10r
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Standartní určitě ne.
Marián Kyral avatar 16.2.2011 09:15 Marián Kyral | skóre: 29 | blog: Sem_Tam | Frýdek-Místek
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Odpovědět | Sbalit | Link | Blokovat | Admin
Nedávno jsem viděl přednášku o Systemd z Linux.conf.au. Koncept a některé idee jsou hodně zajímavé. Inicializace všech soketů už jádrem, start jednotlivých služeb (http, mysql, …) až když danou službu opravdu potřebují - přistoupí k soketu, nahrazení většiny startovacích skriptů jednoduchým konfiguračním souborem.

Nash je sice zajímavý, ale systemd jde dál.
pavlix avatar 16.2.2011 12:02 pavlix | skóre: 54 | blog: pavlix
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Já na FOSDEMu, systemd je geniální věci, ale souvislist nevidím.
Já už tu vlastně ani nejsem. Abclinuxu umřelo.
Marián Kyral avatar 16.2.2011 14:31 Marián Kyral | skóre: 29 | blog: Sem_Tam | Frýdek-Místek
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Narážel jsem na přepis startovacích skriptů z bash do nash. Se systemd to není v podstatě třeba. Jsou z toho přepisu v Debianu nějaké konkrétní výsledky? O kolik se zkrátil boot?
16.2.2011 17:42 merlin111 | skóre: 15
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Pokud si dobře pamatuju tak samotný přechod ušetřil řádově několik vteřin. Nicméně pak přidali závislostní bootovaní což proces znatelně urychlilo subjektivně o desítky vteřin.
Každá ulice je slepá jen do té doby, než si opatříš buldozer.
David Watzke avatar 16.2.2011 18:01 David Watzke | skóre: 74 | blog: Blog... | Praha
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
O desítky vteřin?? To jako zrušili boot úplně? :-D
“Being honest may not get you a lot of friends but it’ll always get you the right ones” ―John Lennon
16.2.2011 18:22 merlin111 | skóre: 15
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Nevím, určitě to závisí na hardware. Nedávno jsem na jednom pc aktualizoval z Lenny na Squeeze a tam ten rozdíl byl docela citelný, pravda je že jsem tam nedával blbiny jeko exim, torrent, fglrx... Nebijte mě, ale boot trvá tak 20 - 30 s včetně bios.
Každá ulice je slepá jen do té doby, než si opatříš buldozer.
David Watzke avatar 16.2.2011 18:38 David Watzke | skóre: 74 | blog: Blog... | Praha
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Nebijte mě, ale boot trvá tak 20 - 30 s včetně bios.
Jasně, takhle dlouho trvá i na Arch Linuxu, kterej má initskripty v Bashi. Takže zkrácení o desítky sekund by bylo v podstatě zrušení bootu :-D
“Being honest may not get you a lot of friends but it’ll always get you the right ones” ―John Lennon
Jakub Lucký avatar 16.2.2011 20:04 Jakub Lucký | skóre: 40 | Praha
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Nebylo to spíš přechodem na concurrency boot?
If you understand, things are just as they are; if you do not understand, things are just as they are.
16.2.2011 20:28 merlin111 | skóre: 15
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Každá ulice je slepá jen do té doby, než si opatříš buldozer.
16.2.2011 21:13 merlin111 | skóre: 15
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Aha,... takže dependency boot není ani tak pro urychleni, ale spíš proto, aby se vývojáři nemuseli starat o pořadí init scriptů.
Každá ulice je slepá jen do té doby, než si opatříš buldozer.
16.2.2011 21:15 Michal Kubeček | skóre: 72 | Luštěnice
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Spíš bych řekl proto, aby se o něj museli starat jen v nezbytně nutné míře: určit, co na čem závisí.
16.2.2011 09:18 chochi | skóre: 29 | Praha
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Odpovědět | Sbalit | Link | Blokovat | Admin
Konstrukce typu x=$((x+1)) urcite neni kompatibilni s Bourne Shell.
$ sh -c 'x=1; x=$((x+1))'
sh: syntax error at line 1: `x=$' unexpected
$ sh -c 'x=1; x=$(($x+1))'
sh: syntax error at line 1: `x=$' unexpected
To je feature az od Korn Shell.
David Watzke avatar 16.2.2011 10:03 David Watzke | skóre: 74 | blog: Blog... | Praha
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Pravda, omlouvám se. Opravíme to podle komentáře #1.
“Being honest may not get you a lot of friends but it’ll always get you the right ones” ―John Lennon
16.2.2011 09:20 Milan Vančura | skóre: 2
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Odpovědět | Sbalit | Link | Blokovat | Admin
Při předělávce skriptu z bashe na sh je potřeba pohlídat různé konstrukce nejen z pohledu výkonnosti či přehlednosti kódu, ale i na vedlejší efekty či skrytě odlišné chování. Občas je to pekelně zákeřné, obzvlášť když ten samý skript píšeme v #!/bin/sh právě proto, aby běžel zároveň na strojích disponujících různými shelly (čili např. zálohovací skript, který má běžet na Linuxech, HP-UX, Solarisech a AIX).

Některé zákeřnosti jsou vidět snáze, např. pokud se příkaz read dostane do podprocesu, těžko si šáhneme na proměnné z jeho výstupu:

read auto <<< $(echo nazdar | tr nr 'M '); echo $auto # Funguje, protože proměnná $auto je ve stejném shellu

echo nazdar | tr nr 'M ' | read auto; echo $auto # Většinou nefunguje, protože proměnná $auto zmizí i se svým podprocesem, viz níže

A někdy vás to opravdu překvapí - jako když ten příkaz read z příkladu výše začne najednou někde fungovat - a objevíte tím pádem nenápadnou větu z manuálové stránky ksh, sekce pipeline:
Each command, except possibly the last, is run as a separate process;
A to jsou jen dvě drobnosti namátkou. Navíc autor článku správně zmiňuje fakt, že nemá smysl přepisovat konstrukce ve skriptu, když by člověk zůstal u GNU rozšíření ostatních programů - takže se k tomu přidají další konstrukce obcházející tyto nedostatky - a kód roste a roste...

Zkrátka, je to procházka růžovým sadem (z pohledu ostatních - přeci si jen hraješ se skripty, co na tom je? Žádné programování kernelu...), kde v každém růžovém keři je minimálně jeden Semtex (z pohledu těch, co to zkusili). Kdysi jsem měl dvě nabídky práce: buď dělat v céčku a s Oracle databází nebo za o polovinu vyšší plat jít do jedné banky spravovat jejich shellové skripty. Zvolil jsem to první - a když jsem pak pomáhal s pár skripty pro zákazníky, pochopil jsem, jak moc mě v té chvíli osvítilo, že jsem se nenechal penězi zlákat...
16.2.2011 09:28 alkoholik | skóre: 40 | blog: Alkoholik
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Programovat v C pro Oracle je teda vyhra. Treba u nas si kolega napsal knihovnu i_hate_oci.
;)
16.2.2011 10:36 Milan Vančura | skóre: 2
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Přesně tak, také jsem od toho utíkal, jak se dalo - ale i tak to bylo neporovnatelné s těmi shellovými skripty :-)
16.2.2011 10:08 Martin Mareš
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Viz nezapomenutelný výrok Larryho Walla: "It is easier to port a shell than a shell script." :-)
16.2.2011 10:39 Milan Vančura | skóre: 2
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Zní to jako by věděl, o čem mluvil :-)
16.2.2011 13:47 Ivan
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Ani kdyz bashismy odstranite tak si nepomuzete. Napriklad takovy Korn shell. Ten je ve verzi ksh200(to co je v RHEL5) zamerne zpetne nekompatibilni s verzi ksh93 ktera se vyskutuje na komercnich Unixech.
Ruža Becelin avatar 16.2.2011 15:52 Ruža Becelin | skóre: 40 | blog: RuzaBecelinBlog
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
V RHEL5 je ksh93, ktery vznikl jako open source fork tehdy proprietarniho ksh88. Vetsina konstrukci je nastesti stejnych. Ksh88 je treba v AIX nebo Solarisu. Momentalne prevadime ksh skripty z AIX na RHEL, tak jsem zvedavy, co prestane fungovat :-P
16.2.2011 17:01 Ivan
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Ja mam na RHEL 5.2 nainstalovan ksh-20060214-1.7. Je to prerekvizita pri instalaci Oracle. Tohle ksh neni kompatibilni s pdksh treba v tomhle:
function a {
typeset var localvariable = 0;

}
V tomto pripade promenna localvariable neni lokalni a je inicializovana pouze jednou. Pokud by ale byla fce "a" deklarovana jako "function a()" tak by byla localvariable inicializovana pri kazdem volani.

Amarok avatar 16.2.2011 10:18 Amarok | skóre: 33 | blog: blogoblog
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Odpovědět | Sbalit | Link | Blokovat | Admin
Jestli clanek vzniknul na zaklade zverejneni meho odhodlani pouzivat pro shellove skripty Dash, tak me to tesi :-) Aspon dalsi zajimavy clanek tady na abc.
GNUniverse - May the source be with you...
David Watzke avatar 16.2.2011 12:58 David Watzke | skóre: 74 | blog: Blog... | Praha
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Ano, asi to tak je, napadlo to Doliho.
“Being honest may not get you a lot of friends but it’ll always get you the right ones” ―John Lennon
16.2.2011 11:18 Michal Kubeček | skóre: 72 | Luštěnice
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Odpovědět | Sbalit | Link | Blokovat | Admin
Lidé v Bashi často používají příkaz test voláním [[, …

Tady asi mělo být spíš nahrazují než používají.

16.2.2011 18:09 Jiří Benc | skóre: 13 | blog: ublog | Praha
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Odpovědět | Sbalit | Link | Blokovat | Admin
Chování minimálního shellu (tedy onoho "sh") je definováno POSIXem (příslušná kapitola v poslední verzi zde, rozhodně lze doporučit k přečtení). Příliš nechápu, proč je v článku sh volně zaměňován s dashem. Skoro mi až přijde, že v tom sám autor má tak trochu zmatek, slovo POSIX se v článku neobjevuje ani jednou...
Luboš Doležel (Doli) avatar 16.2.2011 18:54 Luboš Doležel (Doli) | skóre: 98 | blog: Doliho blog | Kladensko
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Dash je jediný důvod, proč teď někdo tohle řeší. Je to jediná implementace, se kterou se lze pod sh setkat na Linuxu v běžných distribucích.

Takže většinu lidí nezajímá POSIX, většina lidí bude hledat, jak něco "rozchodit pod Dashem".
16.2.2011 19:28 qwertz
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Odpovědět | Sbalit | Link | Blokovat | Admin
Jaky je rozdil mezi? Co je lepsi?
echo $(whoami)
echo `whoami`
btw, jak se da napsat ` ve windows?
Jardík avatar 16.2.2011 19:39 Jardík | skóre: 40 | blog: jarda_bloguje
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Blbě, Alt+nějaká číselná kombinace. Na druhou stranu tam znak ` nikde nepotřebujete, leda byste byl úchyl používající šmejďárnu typu cygwin.
Věřím v jednoho Boha.
Jendа avatar 17.2.2011 18:38 Jendа | skóre: 78 | blog: Jenda | JO70FB
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Na druhou stranu tam znak ` nikde nepotřebujete, leda byste byl úchyl používající šmejďárnu typu cygwin.
A co pracovat vzdáleně na nějakém unixu?
David Watzke avatar 16.2.2011 19:47 David Watzke | skóre: 74 | blog: Blog... | Praha
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Rozdíl v sh je tento:
$ echo $(whoami)
syntax error: `(' unexpected
$ echo `whoami`
dave
V bashi je ovšem často pohodlnější používat $( ). Je to přehlednější (zvlášť při vnořování), nedá se to snadno zaměnit.

A nakonec rozdíl (v bashi):
When the old-style backquote form of substitution is used, backslash retains its literal meaning except when followed by $, `, or \. The first backquote not preceded by a backslash terminates the command substitution. When using the $( command ) form, all characters between the parentheses make up the command; none are treated specially.
“Being honest may not get you a lot of friends but it’ll always get you the right ones” ―John Lennon
16.2.2011 20:37 petr_p | skóre: 59 | blog: pb
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Máte rozbitý shell. POSIX substituci $() definuje.
David Watzke avatar 16.2.2011 20:41 David Watzke | skóre: 74 | blog: Blog... | Praha
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
V dashi mi to jde, na "sh" v Solarisu ne.
“Being honest may not get you a lot of friends but it’ll always get you the right ones” ―John Lennon
17.2.2011 12:31 tomasgn | skóre: 23 | JN89GE
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Solaris je takovy zabavny system, kde ledasco funguje jinak, nez je zvykem. zvlast na starsim systemu ;-)
$ uname -a
SunOS srv 5.6 Generic_105181-39 sun4u sparc SUNW,Ultra-5_10

$ echo $(whoami)
ksh: whoami:  not found

$ echo $(who am i)
xxxxxxx pts/1 Feb 17 12:20 (xxxxxxxxxxx)

$ sh
$ echo $(whoami)
syntax error: `(' unexpected
17.2.2011 15:14 poridge
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Zase někdo, kdo tvrdí, že něco nejde a je divné předtím, než čte aspoň ty manpages, když už ne dokumentaci. Solaris se chová podle dokumentace, i na starším systému. whoami je BSD. Takže co takhle /usr/ucb (Unix Common Base)? who am i je něco naprosto jiného. Trochu pokory prosím a než vyřknete výrok o podivnosti, ujistěte se, že problém není v nedostatku vlastní informovanosti. Co byste řekl o HP-UXu? A i tam máte možnost chování podle normy, stačí číst před vynesením rozsudku.

/bin/sh na Solarisu - shell s názvem sh není zaručeně totéž jako POSIX/XPG4 shell a Bourne shell vážně není normovaný standard sám o sobě, a to nikdy a nikde. Mimochodem, základ POSIXového shellu je ksh88, nikoli Bourne shell. Dokumentace k příslušnému systému napoví, kde jsou BSD, SYSV nebo POSIX/XPG4 nástroje, případně co musíte udělat, aby se vám příkazy chovaly podle příslušné normy nebo zvyku.

Takže XPG4 sh na Solarisu? A co takhle /usr/xpg4/bin/sh?
# uname -a
SunOS dedek 5.6 Generic_105181-39 sun4u sparc SUNW,Ultra-5_10
# exec /usr/xpg4/bin/sh
# echo $(/usr/ucb/whoami)
juzr
Vyřešeno, byť systém už dávno není podporován, léta na něj neexistují patche a jen blázen by nechával v produkci cokoli staršího než Solaris 9. A po celou dobu až do současných verzí je to pořád stejné, na stejném místě a se stejným chováním.

A překvapení, i AIX má /usr/ucb a hle, AIXovský /bin/sh je ve skutečnosti normovaný ksh a většina toolů v AIXu je prostě POSIX/XPG4.

Pokud chcete přenositelnost, nezbývá než číst dokumentaci (:-), užívat POSIX/XPG4 nástroje a upravovat cesty. Shell? ksh. To je normované a konzistentní. awk? nawk. sed, ps atd - opět hledejte POSIXové. Složité konstrukce, výrazy apod? Proč v shellu?

Ve start skriptech systému vážně netřeba speciálních konstrukcí a už vůbec ne přenositelnosti. A startovat aplikaci bude stejně lepší s ksh (nebo perl, etc). Buď totiž startujete obecnou aplikaci a potřebujete přenositelnost, ale tehdy vám stačí jednoduchý sh wrapper kolem skutečného start skriptu, a ten už může být v čemkoli a to cokoli klidně distribuujte s aplikací. Nebo děláte komplikovanou akci při startu systému (nebo v udev na Linuxu a tak), která musí doběhnout i s nenamountovaným /usr apod, ale pak to stejně bude silně system-specific a šijete to tedy na míru daného shellu a systému.

Přeji trpělivost, dobré oči a pěkný den.
17.2.2011 15:49 tomasgn | skóre: 23 | JN89GE
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Zase někdo, kdo tvrdí, že něco nejde
netvrdim, ze neco nejde. jen jsem reagoval na skutecnost, ze vychozi nastaveni muze nekoho prekvapit, pokud se systemem bezne nepracuje.

takze jste se zbytecne rozepisoval, ale treba to nekomu jinemu poskytlo zajimave informace.
17.2.2011 17:56 poridge
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
OK, pravda, neřekl jste "nejde". Ale pokud jste věděl o XPG4 a UCB, proč jste to neuvedl? Jaký smysl pak má takový výkřik, když nenabídnete ostatním existující a snadné řešení? Někdo, kdo z linuxu nevytáhl nikdy paty pak prostě získá dojem až příliš častý, a to právě že na non-linuxech "je to divné a spousta věcí nechodí".

Bohužel až příliš často je slyšet "divné, nanic, legrační" jako synonymum "chová se jinak než linux". A od stejných lidí bývá obvykle slyšet stížnosti na jiné lidi, kterým vadí, že se linux chová jinak než windows. Což místo vypichování rozdílů lidem poradit, jak dosáhnout co nejvíc konzistentního prostředí nezávislého na platformě, když to víte?

"Kdo chce, hledá způsob. Kdo nechce, hledá důvod."
21.2.2011 22:58 daneel
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
No, poměrně tlustá skripta z roku 2002 s názvem "POSIX Shell Programming" říkají, že forma se znakem ` je "deprecated". Tak nějak jsem si myslel, že Bash o sobě tvrdí, že je v zásadě POSIX compliant.

Jenže také říkají, že "
[ conditional_expr ] # Provided for Bourne shell compatibility (obsolete)
[[ conditional_expr ]] # POSIX and Korn shell specific syntax (preferred)
...

Tak nevím...
Josef Kufner avatar 16.2.2011 20:06 Josef Kufner | skóre: 70
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
I ve windows je ` na klávese vedle jedničky... pokud máš anglickou klávesnici.
Hello world ! Segmentation fault (core dumped)
16.2.2011 20:06 Michal Kubeček | skóre: 72 | Luštěnice
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Úplně stejně jako v Linuxu, obvykle je to klávesa nalevo od jedničky.
Jendа avatar 17.2.2011 18:40 Jendа | skóre: 78 | blog: Jenda | JO70FB
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
I na české? Matně si vzpomínám, že se na to muselo nějak složitěji.
17.2.2011 19:31 Michal Kubeček | skóre: 72 | Luštěnice
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Nikdy jsem necítil potřebu programovat nebo "adminovat" s českou klávesnicí. Když tu a tam potřebuji během takové činnosti napsat něco s diakritikou, tak na tu chvíli přepnu na českou a pak zase zpátky. Přijde mi to podstatně praktičtější než psát všechny symboly (kterých je v programech nebo při správě systému mnohem víc než znaků s diakritikou) pomocí modifikátorů nebo dokonce jejich kombinací.
Jendа avatar 18.2.2011 15:54 Jendа | skóre: 78 | blog: Jenda | JO70FB
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Mně zase přijde praktičtější zvyknout si na jedno rozložení a pak používat to. Ale je pravda, že takových jako já asi moc není.
nebo dokonce jejich kombinací
Pomocí kombinace se na české píše jenom pípa |, ale na spoustě klávesnic je „pička key“ (klávesa označovaná v GNOME jako <|>), která píše | a \.
Jakub Lucký avatar 18.2.2011 16:10 Jakub Lucký | skóre: 40 | Praha
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Proč kombinací? já píšu pípu pomocí AltGr+w
If you understand, things are just as they are; if you do not understand, things are just as they are.
Jendа avatar 18.2.2011 16:24 Jendа | skóre: 78 | blog: Jenda | JO70FB
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Hmm, na to jsem si nikdy nezvykl.
18.2.2011 16:17 Michal Kubeček | skóre: 72 | Luštěnice
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Namátkou mne napadá třeba vlnka nebo cokoli, co se na anglické píše se shiftem. Jen pro jistotu: pamatovat si pro každý symbol, na jakém písmenu ho dostanu bez shiftu, to ani omylem. Navíc jakákoli kombinace pravého altu s písmenem pravé ruky je krkolomná i bez shiftu.
Jendа avatar 18.2.2011 16:26 Jendа | skóre: 78 | blog: Jenda | JO70FB
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Namátkou mne napadá třeba vlnka nebo cokoli, co se na anglické píše se shiftem.
Tu píšu RAlt + A. Z písmenek si pak pamatuju už jenom BN ({}).
18.2.2011 17:12 imploder | skóre: 11
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Mně zase přijde praktičtější zvyknout si na jedno rozložení a pak používat to. Ale je pravda, že takových jako já asi moc není.
nebo dokonce jejich kombinací
Já taky používám pořád českou QWERTY. Ze známých osobností pak minimálně RH a to už něco znamená :-)
17.2.2011 16:29 xHire | skóre: 21 | blog: Linuxovník
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
AltGr-H nejede? (Případně Ctrl-Alt-H?) Většinou mi tyhle základní zkratky fungovaly vždy, ale u ` si nejsem jistý…
Kryptoměny a bločenka.
17.2.2011 18:07 Ales Hakl
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
` se ve windows pise stejne jako vsude jinde. Jediny problem je, ze na ceske klavesnici maji windows tam kde byl drive ` od dob Windows 95 apostrof dopredny (coz dava smysl, vzhledem k tomu, ze ten je precijenom casteji pouzivany)

Rozdil je v tom, ze expanze zapsana s ` je celkem neprehledna a snadno muze byt matouci (a mimochodem rozbiji zvyraznovani syntaxe v emacsu :)).
18.2.2011 15:20 hefo
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Neviem ako inde vo Windows, ale u mna so slovenskou klavesnicou Alt+7 (tu je to: `) ;-) A ako som skusal, tak na anglickej je to ta klavesa vedla "1" (niekomu to nefunguje?)...
16.2.2011 20:15 camel1cz | skóre: 25
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Odpovědět | Sbalit | Link | Blokovat | Admin
Zajímavý článek... zrovna včera jsem bashismus našel v startup scriptu Oracle XE... no teď už se směju :-D
Petr Tomášek avatar 21.2.2011 11:18 Petr Tomášek | skóre: 39 | blog: Vejšplechty
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Odpovědět | Sbalit | Link | Blokovat | Admin
Popravdě, ukažte mi moderní systém, který by bash nepoužíval. Podle mě je tohle už kapku praštěné...
multicult.fm | monokultura je zlo | welcome refugees!
Amarok avatar 21.2.2011 18:22 Amarok | skóre: 33 | blog: blogoblog
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
Debian.
GNUniverse - May the source be with you...
Jakub Lucký avatar 21.2.2011 18:36 Jakub Lucký | skóre: 40 | Praha
Rozbalit Rozbalit vše Re: Odstraňujeme bashismy
IMHO třeba Solaris, BSD, v Debianu se přestal používat ve skriptech na úkor o dost výkonnějšího Dash...
If you understand, things are just as they are; if you do not understand, things are just as they are.
⧠ A = 0 avatar 21.2.2011 19:44 ⧠ A = 0 | skóre: 11 | blog: Technokratovo_zrcadlo | Helsinki
Rozbalit Rozbalit vše Grammar Nazi
...se přestal používat ve skriptech na úkor o dost výkonnějšího Dash...
Ach jo.
Nevolte zmrdy.
Amarok avatar 21.2.2011 20:06 Amarok | skóre: 33 | blog: blogoblog
Rozbalit Rozbalit vše Re: Grammar Nazi
...se přestal používat ve skriptech na úkor o dost výkonnějšího Dash...
Ach jo.
?? Ach ne.
GNUniverse - May the source be with you...
Jakub Lucký avatar 21.2.2011 20:06 Jakub Lucký | skóre: 40 | Praha
Rozbalit Rozbalit vše Re: Grammar Nazi
Jo, tak to dopadá když člověk dělá víc věcí najednou... omlouvám se...
If you understand, things are just as they are; if you do not understand, things are just as they are.
Amarok avatar 21.2.2011 20:35 Amarok | skóre: 33 | blog: blogoblog
Rozbalit Rozbalit vše Re: Grammar Nazi
Tak to jsem byl taky mimo, ja myslel, ze se jedna o zvyrazneni kvuli gramatice. :-D
GNUniverse - May the source be with you...

ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.