Kis-nagybetű konverzió

A hülye mkisofs miatt át kellett neveznem egy csomó fájlt kisbetűsről nagybetűsre (szerencsére ékezetes nincs a készletben). Az adott dobozban egy meglehetősen korlátozottnak tekinthető Linux-like környzet lakozik Busybox-szal, és egy-s-más kiegészítővel, amit az idők során rátelepítettem. Legnagyobb meglepetésemre a jól bevált módszer - a hozzá szükséges segédeszköz híjján - nem működött, így elkezdtem a favágó (kézzel történő) átnevezés helyett kitalálni, hogy a szűkös parancskészlettel mit lehetne tenni. Ezek jutottak eszembe:

1. tr


for i in * ; do
mv "$i" "`echo $i | tr '[a-z]' '[A-Z]'`"
done

- ezzel szoktam általában, de itt tr: command not found vagy valami hasonló volt az eredmény.

(A továbbiakban már csak a | és a záró " közötti rész jön)

2. dd


dd conv=ucase

- no itt a BusyBox dobott hibát, ugyanis a beépített dd nem ismeri a conv= paramétert (de cserébe ha nehezen is, de megtanultam, hogy hogyan kell lekérdezni busybox-os beágyazott parancs help-jét; pl.: "busybox dd --version" érdekes módon a help-et is kiírja :-) és még néhány egyéb kipróbált beépített parancsra működött).

3. sed


sed -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'

- végül ezzel oldottam meg, bár tény, itt is szögletes zárójellel kisérleteztem először, mint a tr-nél - szerencsére a tesztnél ez elég hamar kibukott, hogy nem OK. (Asszem ez is beépített busybox parancs, de nincs annyira lebutítva, mint a dd.)

4. perl


perl -pne 'tr/a-z/A-Z/;'

- ha már ugye van a perl-nek tr parancsa. Ráadásul itt nem is kell kiírni a teljes ABC-t. Persze ehhez telepítve kell legyen perl, de az valamiért szokott lenni az ilyenekben. :-) Amúgy természetesen használható lenne a sed-ekvivalens y parancs is a tr helyett, azzal ugye spórolnék még 1 karakter gépelést.


perl -pne 'y/a-z/A-Z/;'

(Persze ez a verzió szigorúan csak azért szerepel a listában, mert a sed is szerepelt.)

5. awk


awk '{print toupper($0);}'

- ez utólag jutott eszembe, és egyáltalán nem biztos, hgy van awk a masinán (gawk van amúgy, én valamilyen awk-t fel szoktam rakni).

6. És a legegyszerűbb, bash (itt az egész cső megspórolható):


mv "$i" "${i^^}"

- lehetett volna így is, ugyanis a bash-nak eleve van egy beépített konverziója. De bash nincs telepítve a dobozkán, mert minek - azaz ez is bukott.

No ennyi, ezek jutottak kb 10 perc alatt az eszembe, ha még eszembe jut valami hordozható, majd még leírom.

Szerk (2013. okt. 3):

7. ksh/bash:

Van a Korn-shellnek (ksh) egy erre a funkcióra szintén használható megoldása, amely egyébként bash alatt is működik. A változók bizonyos jellemzőit lehet állítgatni a typeset nevű paranccsal. (Bash alatt declare-nek hívják, de szerencsére kompatibilitási okokból mind a két forma működik.) Azaz:


typeset -u j
for i in * ; do
j="$i"
mv "$i" "$j"
done

(Ha a typeset "-u" helyett "-l" paramétert kap, akkor nem Uppercase, hanem Lowercase - azaz kisbetűsítést végez. Az attribútum beállítása csak értékadáskor hat, egy változót utólag csak két lépésben lehet átalakítani:


v=VALami
echo "$v" # -> VALami
typeset -u v # értékadáskor NAGYBETŰSÍT
echo "$v" # nem változik
v="$v" # most átalakul
echo "$v" # -> VALAMI
typeset -l v # értékadáskor kisbetűsít
echo "$v" # -> VALAMI
v="$v" # most átalakul
echo "$v" # -> valami

(A pdksh annyiban eltér a bash/ksh93 viselkedésétől, hogy az attribútum beállítása azonnal konvertál, nem kell neki a "fölösleges" értékadás.)

Hozzászólások

Nagy köszönet! Pont ma bűvészkedtem a cégnél a tr-es megoldással ;)

--
A gyors gondolat többet ér, mint a gyors mozdulat.

Apró javítás:

a perl -pne kapcsolói közül az n felesleges, ha a p-t már megadtad;

továbbá a perlnek van egy olyan függvénye, hogy "uc", ami nagybetűssé alakítja az argumentumaként kapott sztringet vagy a $_-t. Tehát:

perl -pe '$_=uc'

vagy kevésbé felvágósan

perl -ne 'print uc'

Ez abból a szempontból is jobb, mint a te tr///-es megoldásod, hogy az ékezetes karaktereket is nagybetűs megfelelőikre változtatja. (Az alapproblémád, a mkisofs számára ehető fájlnevek szempontjából persze ez mit sem ér, oda inkább az ékezetes karakterek intelligens éktelenítése kell, ami egy nagyságrenddel nehezebb feladat.)

n+1. alternatívaként a find és xargs valamilyen kombinációjával is ki lehet váltani a for ciklust.

Az ékezetes karakterekben biztos vagy? Szerintem minimum platformfüggő:


$ perl --version

This is perl, v5.10.1 (*) built for i686-cygwin-thread-multi-64int
(with 12 registered patches, see perl -V for more detail)

Copyright 1987-2009, Larry Wall

Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.

Complete documentation for Perl, including FAQ lists, should be found on
this system using "man perl" or "perldoc perl".  If you have access to the
Internet, point your browser at http://www.perl.org/, the Perl Home Page.


$ perl -ne 'print uc'
öüóőúéáűí
öüóőúéáűí

$ 

Uhh.

Figyelmetlenül olvastam az uc leírását. Valójában nagybetűssé változtatja az ékezetes karaktereket is, HA az use locale be van kapcsolva ÉS ami szerintem ékezetes karakter, az a locale szerint is az ÉS a karakterkódolás is rendben van befelé-kifelé.

Ez nálam konkrétan az alábbi szörnyeteggel valósul meg:


$ LC_CTYPE="hu_HU.utf8" perl -mlocale -ne'BEGIN{binmode(STDIN,":utf8");binmode(STDOUT,":utf8")} print uc'
árvíztűrő tükörfúrógép
ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP

$

Szerk: az LC_CTYPE állítása és a -mlocale nem is kell. De a karakterkódolásra érzékeny.

Windowson nem tudom megtippelni, hogy a fentiekből melyik kell a sikerhez.

A -p -n jogos. (Eredetileg csak-n volt, es kezzel hivtam print-et, utolag ugrott csak be, hogy van -p is, de oly ritkan hasznalom a perl opciokat, hogy a franc emlekezett ra.)

A "print uc" forma egyszeruen eszembe se jutott, hiszen (mint irtam is) a tr/sed iranyabol jottem, arra allt ra az agyam - ha korabban ugrik be az awk forma, mint a perl, valszeg hamarabb jottem volna ra arra, hogy perlben is lehet kb ugyanugy. Igazabol ugy gondoltam, hogy perl-ben mar van megoldas, es nem kezdtem el tovabb ragozni - a cel inkabb a lehetseges szoftverek felkutatasa volt es nem adott szoftverrel a legtobb/legoptimalisabb/stb. Ettol fuggetlenul kosz a kiegeszitest, hasznos.

Ha pedig ekezetes karakterek is lettek volna, helybol nem igy kezdek neki a dolognak. (Bar pl. FreeBSD-n helyes LANG beallitas eseten a tr korrekten nagybetusiti az ekezeteket is.

tr '[[:lower:]]' '[[:upper:]]' 

forma kell ugyan a szimpla a-z helyett, de az meg belefer. Ellenben a dd nem, a tobbit most nem kezdtem tesztelni.)

Vegul a find/xargs - kosz, itt is a kiegeszitesert, bar nem a ciklus kivaltasa, hanem a nagybetusites volt a cel egy adott konyvtarban. Ez utobbira keresnek meg "kvazi"-szabvanyos unixos eszkozt, de nem nagyon ugrik be tobb. (Pontosabban kb 10 perce gyokolok azon, hogy a vi a :s parancsban tud olyat (meg a perl is), hogy 's/.*/\U&\E/' - sajnos ezen a ketton kivul most nem sikerult olyan progit talalnom, amelyik a regexp kezelesnek ezt a kellemes reszet ismerne. Abban biztam, hogy pl. a pax -s opciojaval meg lehet oldani, de folyamatosan nyafog a modositok miatt, szoval az se jo latszolag.)

prename

--
Live free, or I f'ing kill you.