Portál AbcLinuxu, 11. května 2025 10:01

Dotaz: BASH | Rozdělení stringu

31.7.2012 17:03 Petr
BASH | Rozdělení stringu
Přečteno: 905×
Odpovědět | Admin
Ahoj, mám proměnou ve které je text oddělený znakem | a potřebuji je rozdělit do dvou proměnných do první proměnné uložit to co je před znakem | a do druhé to co je za znakem |. Poradí prosím nějaký frajer? ;-) Moc moc děkuji!
TEXT="/etc/apache2/host|/tmp/apache2/host"

Řešení dotazu:


Nástroje: Začni sledovat (0) ?Zašle upozornění na váš email při vložení nového komentáře.

Odpovědi

mess avatar 31.7.2012 17:08 mess | skóre: 43 | blog: bordel | Háj ve Slezsku - Smolkov
Rozbalit Rozbalit vše Re: BASH | Rozdělení stringu
Odpovědět | | Sbalit | Link | Blokovat | Admin
Třeba tady.
Cez párne mesiace zošíváš vaginy, cez neparne montuješ hajzle.
31.7.2012 17:11 Marble | skóre: 27 | blog: marble
Rozbalit Rozbalit vše Re: BASH | Rozdělení stringu
Odpovědět | | Sbalit | Link | Blokovat | Admin

${TEXT%|*} a ${TEXT#*|}

Případně obecněji pro libovolný počet částí: IFS='|' toks=($TEXT); echo "${toks[0]}, ${toks[1]}, ..." (mezi nastavením IFS a přiřazením poli nemá být ani konec řádku, ani středník, aby se po přiřazení zachovalo původní IFS).

31.7.2012 17:15 Petr
Rozbalit Rozbalit vše Re: BASH | Rozdělení stringu
Tak to jste opravdu dobrej, smekám.. a dal by jste i tři?
TEXT="/etc/apache2/host|/tmp/apache2/host|/var/apache2/host"
31.7.2012 17:18 l4m4
Rozbalit Rozbalit vše Re: BASH | Rozdělení stringu
Stačí si přečíst tu část odpovědi s ,libovolný počet částí`.
31.7.2012 17:31 Petr
Rozbalit Rozbalit vše Re: BASH | Rozdělení stringu
Hm, tak buď to nechápu nebo mi to nejde z jiného důvodu, vypisuje se pořád všechno :(
     IFS="|"
     for READ in $(cat /tmp/data.txt)
     do
          TOKS=($READ)
          ${TOKS[0]}
          ${TOKS[1]}
          ${TOKS[2]}
     done
31.7.2012 17:48 l4m4
Rozbalit Rozbalit vše Re: BASH | Rozdělení stringu
Nevím, co máš přesně v /tmp/data.txt, ale IFS patří do toho přiřazení. Např.:
while read x; do IFS=: y=($x); echo ${y[4]}; done </etc/passwd
4.8.2012 18:03 trish
Rozbalit Rozbalit vše Re: BASH | Rozdělení stringu

mezi nastavením IFS a přiřazením poli nemá být ani konec řádku, ani středník, aby se po přiřazení zachovalo původní IFS.

Rejp, tohle neplatí, nezachová se. Pokud v jednoduchém příkazu není nic jiného než přiřazení (a přesměrování), mění všechna proměnné aktuálního shellu (viz man bash, Simple Command Expansion). (Pokud je, nezmění se žádná z nich.)

I další doteď uvedené příklady změní IFS shellu, což si lze snadno ověřit skrze: set|grep IFS, příp. povšimnout si na jaká slova se nadále expanduje proměnná TEXT: kupř. pomocí echo $TEXT "$TEXT" (dělení slov dle $IFS není totéž a tehdy, kdy se rozpoznávají jednotlivá slova-tokeny (ty v bashi vždy oddělují znaky: | & ; ( ) < > space tab)).
4.8.2012 18:29 Kit
Rozbalit Rozbalit vše Re: BASH | Rozdělení stringu
Taj si to vyzkoušej, když nevěříš:
LANG=POSIX df
df
První příkaz se vypíše v POSIXu, druhý zase s původní lokalizací.
4.8.2012 18:47 l4m4
Rozbalit Rozbalit vše Re: BASH | Rozdělení stringu
On naráží na něco jiného, na konstrukci
a=b c=d
což skutečně není globální přiřazení c=d s lokálním nastavením a=b, ale globální přiřazení do c i a. Takže to IFS by se mělo raději nastavovat jinde...
6.8.2012 05:38 Ash | skóre: 53
Rozbalit Rozbalit vše Re: BASH | Rozdělení stringu
Taj si to vyzkoušej, když nevěříš:
TEXT="/etc/apache2/host|/tmp/apache2/host"

echo "Old IFS: $IFS"

IFS='|' toks=($TEXT); echo "${toks[0]}, ${toks[1]}, ..."

echo "New IFS: $IFS"
Old IFS:

/etc/apache2/host, /tmp/apache2/host, ...
New IFS: |
6.8.2012 17:00 Marble | skóre: 27 | blog: marble
Rozbalit Rozbalit vše Re: BASH | Rozdělení stringu
Jasně, máš pravdu. Díky za komentář, mně to vůbec nedošlo. :-/ Takže zbývá asi jen uložit původní hodnotu a přiřadit zpátky (anebo si být jistý, že změna IFS zbytku scriptu nevadí).
7.8.2012 01:19 trish
Rozbalit Rozbalit vše Re: BASH | Rozdělení stringu
Nejspíš nevadí, jinak by se tazatel ozval sám. Tedy, doufám. :)

Ad čisté (prakticky krátké) řešení. Buď jak píšeš anebo skrz funkci:
moje() { local IFS=\|; toks=($TEXT);}

prirad() { local IFS=$1; eval $2=\(\$$3\);}
prirad \| toks TEXT
7.8.2012 01:50 trish
Rozbalit Rozbalit vše Re: BASH | Rozdělení stringu
//a samosebou dřív nebo později prospěje kontrola počtu parametrů:
prirad() { [ $# -eq 3 ] || return 1; local IFS=$1; eval $2=\(\$$3\);}
7.8.2012 10:14 trish
Rozbalit Rozbalit vše Re: BASH | Rozdělení stringu
i když, a zejména vzhledem k výše řečenému (plus bez dalšího procesu, přestože konstrukce [[]] mi jinak není úplně sympatická), by bývalo mělo být:
prirad() { [[ $# -eq 3 ]] || return 1; IFS=$1 eval $2=\(\$$3\);}

ráno (někdy i může být) moudřejší večera :)
9.8.2012 15:02 Ash | skóre: 53
Rozbalit Rozbalit vše Re: BASH | Rozdělení stringu
Konstrukce [ ] byla v pořádku, náhradou za [[ ]] jste zde nic nezískal. Změnou použití IFS rovněž ne. Čeho jste vlastně chtěl dosáhnout?
9.8.2012 21:51 trish
Rozbalit Rozbalit vše Re: BASH | Rozdělení stringu
Někde hluboko mám zafixováno, že se u jisté třídy případů [[ a [ chovaly trochu jinak (Nevím už jistě, oč přesně šlo, ani nemám teď sílu pročítat man, je-li tomu tak v něčem teď.) a že (pro mne přátelštější) [ není builtin bashe (což možná vždycky mylně, díky Michalu Kubečkovi za info). Ad druhá připomínka: imho je druhý zápis elegantnější, nic víc. Nač jsi chtěl přijít?
9.8.2012 23:25 Ash | skóre: 53
Rozbalit Rozbalit vše Re: BASH | Rozdělení stringu
Mezi [ a [[ je řada rozdílů, obecně lze říct že [ má smysl jen kvůli kompatibilitě, jinak má spíš nevýhody, [[ je jeho modernější náhrada s více možnostmi. No, z nostalgie je mi také někdy [ sympatičtější ;)
bash$ [ 1 < 2 ] && echo ok
bash: 2: No such file or directory
bash$ [ 1 \< 2 ] && echo ok
ok
bash$ [[ 1 < 2 ]] && echo ok
ok
bash$ a="1 2"
bash$ [ $a = "1 2" ] && echo ok
bash: [: too many arguments
bash$ [ "$a" = "1 2" ] && echo ok
ok
bash$ [[ $a == "1 2" ]] && echo ok
ok
bash$ [[ "$a" =~ ^[[:digit:]]" "[[:digit:]] ]] && echo ok
ok
a=1;b=2
bash$ [[ $a > 0 && $b == 2 ]] && echo ok
ok
bash$ [ "$a" -gt 0 -a "$b" -eq 2 ] && echo ok
ok
Chtěl jsem přijít na to, proč tak důrazně radikálně trváš na tom, že by se to mělo řešit jinak, když tvé původní řešení bylo dobře a nové řešení nepřineslo žádnou změnu či výhodu.
9.8.2012 16:54 Michal Kubeček | skóre: 72 | Luštěnice
Rozbalit Rozbalit vše Re: BASH | Rozdělení stringu
Příkaz test (i se synonymem [ ) je v bashi také builtin.
9.8.2012 15:14 Kit
Rozbalit Rozbalit vše Re: BASH | Rozdělení stringu
Odpovědět | | Sbalit | Link | Blokovat | Admin
echo "$TEXT" | while IFS='|' read a b c; do
  echo "První část: $a"
  echo "Druhá: $b"
  echo "Zbytek: $c"
done
Řešení 1× (trish)
9.8.2012 18:29 Marble | skóre: 27 | blog: marble
Rozbalit Rozbalit vše Re: BASH | Rozdělení stringu

Což má ale jednu podstatnou nevýhodu, totiž že rozsekané proměnné žijí jen v rámci subprocesu s while. V bashi to nicméně jde pěkně vyřešit pomocí while ... done <<<"$TEXT".

Jo, a while je pro jeden řádek samozřejmě zbytečné, takže případně prostě IFS='|' read a b c <<<"$TEXT";

9.8.2012 19:45 Kit
Rozbalit Rozbalit vše Re: BASH | Rozdělení stringu
Zajímavé. Když jsem to zadal ve tvaru
echo "$TEXT" | while IFS='|' read a b c
tak to nefungovalo, ale
IFS='|' read a b c <<<"$TEXT";
funguje bez problémů. Navíc jsi ušetřil jeden proces, takže to vidím jako skvělé řešení.
9.8.2012 20:05 Marble | skóre: 27 | blog: marble
Rozbalit Rozbalit vše Re: BASH | Rozdělení stringu
Pokud jde o rozdíl v pipe, tak je to jednoduchý důsledek toho, že příkazy spojené přes pipe se spouští jako samostatné podprocesy, takže veškeré změny prostředí (včetně proměnných) se "ven" nepromítnou.
9.8.2012 20:11 Kit
Rozbalit Rozbalit vše Re: BASH | Rozdělení stringu
Došel jsem ke stejnému závěru. Takže se neušetřil jeden proces, ale dva. Tím lépe a radostněji.

Založit nové vláknoNahoru

Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

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