Fórum Ubuntu CZ/SK
Ubuntu pro osobní počítače => Software => Příkazový řádek a programování pro GNU/Linux => Téma založeno: Matesax 15 Dubna 2013, 08:00:12
-
Dobrý den,
můžu nějak použít array jako list? Podle všech možných totoriálů, wiki atd. by to mé fungovat mělo - ale nefunguje... :)
while read -r line
do
...
devices[$(($number - 1))] = "${line%:*}"
...
done < /tmp/devices.txt
Number incriminuje v každém kole. Číslo vydává správně - jelikož mi jej vypisuje error:
./install: 19: ./install: devices[@]: not found
Kde @ jsou jednotlivé hodnoty.
Jak to tedy správně udělat?
Děkuji.
-
Řekl bych, že především nepoužívat mezery kolem rovnítka, shell pak místo přiřazení do proměnné výraz zkouší spustit jako program a další znaky za mezerou bere jako argumenty.
-
To vím - toto je projev zoufalství... Když tam mezery nebyly, bral to jako string či co - v erroru byly závorky [] přilepeny k oné proměnné - poli. Zkoušel jsem 62589 kombinací - co na googlu najdete na prvních 6 stranách, to jsem již zkusil... :)
-
http://www.thegeekstuff.com/2010/06/bash-array-tutorial/
**ultimate tutorial by nestacil ?
-
Nevím, co jsi zkoušel, ale například tohle funguje:
#!/bin/bash
n=1
while read -r line
do
devices[$(($n-1))]="${line%:*}"
echo ${devices[$(($n-1))]}
n=$(($n+1))
done < /tmp/devices.txt
-
http://www.thegeekstuff.com/2010/06/bash-array-tutorial/
Jsem zkoušel - slibně ale vypadá to od GdH...
Děkuji.
-
./install: 19: ./install: devices[0]: not found
1) /dev/sda1: UUID="f292a494-9f9f-471d-9e7e-d012596f17bd" TYPE="ext4"
./install: 19: ./install: devices[1]: not found
2) /dev/sda5: UUID="4cf54643-cd1e-4547-9ea2-6058613c7fcf" TYPE="ext4"
./install: 19: ./install: devices[2]: not found
3) /dev/sda6: UUID="0f9c79f2-0cb1-40a2-91d4-80d7adfe9bfd" TYPE="swap"
./install: 19: ./install: devices[3]: not found
4) /dev/sr0: LABEL="VOLUME IDENTIFIER" TYPE="udf"
./install: 19: ./install: devices[4]: not found
5) /dev/sdb: SEC_TYPE="msdos" LABEL="SMA-OP" TYPE="vfat"
To je pro:
devices[$(($number-1))] = "${line%:*}"
Mezera dle mého nehraje roli - jelikož inkriminace number mi funguje...
./install: 19: ./install: devices[0]=/dev/sda1: not found
1) /dev/sda1: UUID="f292a494-9f9f-471d-9e7e-d012596f17bd" TYPE="ext4"
./install: 19: ./install: devices[1]=/dev/sda5: not found
2) /dev/sda5: UUID="4cf54643-cd1e-4547-9ea2-6058613c7fcf" TYPE="ext4"
./install: 19: ./install: devices[2]=/dev/sda6: not found
3) /dev/sda6: UUID="0f9c79f2-0cb1-40a2-91d4-80d7adfe9bfd" TYPE="swap"
./install: 19: ./install: devices[3]=/dev/sr0: not found
4) /dev/sr0: LABEL="VOLUME IDENTIFIER" TYPE="udf"
./install: 19: ./install: devices[4]=/dev/sdb: not found
5) /dev/sdb: SEC_TYPE="msdos" LABEL="SMA-OP" TYPE="vfat"
To je pro:
devices[$(($number-1))]="${line%:*}"
A ještě dotaz - není v proc soubor se stejným obsahem jako je výpis blkid? Aktuálně totiž výstup blkid musím stejně ukládat do tmp - jelikož jej potřebuji číst řádek po řádku - a hádat se s cyklem aby bral string jako zdroj a ne jako cestu k souboru se mi nechce...
Abych to vysvětlil - potřebuji vypsat všechna zařízení tak, aby bylo uživateli jasné o jaké zařízení se jedná. A sice zařízení na které se dá instalovat OS - toto je totiž instalátor mého OS - SMA-OP. No a po vypsání všech zařízení na která by šlo instalovat OS si jedno z nich uživatel vybere číslem - abych z toho výpisu dostal jen cesty k zařízením potřebuji právě to pole - do kterého jen dosadím vstup uživatele jako index - pochopitelně s testem, zda se jedná o číslo...
-
Mezery samozřejmě roli hrají, to že to przníš někde jinde je jiná věc. Dej sem kousek konkrétního samostatně spustitelného kódu (podobně jako jsem to udělal já), který ti nefunguje a já ti řeknu proč. Ten jeden řádek, který tu ukazuješ nic neřekne. Spouštíš to opravdu v Bashi? sh != bash v Ubuntu, ani v Debianu, na to se taky mnoho lidí nachytá. Co má znamenat "inkriminace"?
-
Pouštím to v emulátoru - pro uživatelské pohodlí potřebuji aby to v něm jelo... Inkriminace je navýšení o 1, opakem je dekrementace - snížení o 1 - základní programátorský pojem... ++/--
http://slovnik-cizich-slov.abz.cz/web.php/slovo/dekrementace
Nefunguje mi ten konkrétní řádek - co víc bych měl poslat? Jestli si to chceš zkusit, je to v cyklu while...
#!/bin/sh
number=0
blkid > /tmp/devices.txt
while read -r line
do
number=$(($number + 1))
devices[$(($number-1))]="${line%:*}"
echo "${number}) ${line}"
done < /tmp/devices.txt
-
Zaprvé si inkriminaci pleteš s inkrementací a za druhé ukaž výpis
ls -l /bin/sh
-
Pro jistotu jsem použil:
dpkg-reconfigure bash
Výsledek stejný... Když jsem dal dash, tak to hodilo hlášku - bash ale nastaven již byl...
-
Proč používáš dash, když chceš použít bash? Kurnik zamysli se trochu ;)
-
Čti co píši - dal jsem ho jen na test... Bash mám jako defaultní a stejně to neřeší problém s arrayem - zápis je stejný... Alespoň co jsem naposledy používal dash.
Tedy:
ddd[index]=hodnota
Jenže to nejde... :)
-
Ten skript, co jsi dal spusť takto:
bash /cesta/ke/skriptu
Bash s tim problém nemá.
-
root@sam-eME642:/mnt/Data/SMA-OP# bash ./install
>>> Check for devices
./install: řádek 19: devices[0]: příkaz nenalezen
1) /dev/sda1: UUID="f292a494-9f9f-471d-9e7e-d012596f17bd" TYPE="ext4"
./install: řádek 19: devices[1]: příkaz nenalezen
2) /dev/sda5: UUID="4cf54643-cd1e-4547-9ea2-6058613c7fcf" TYPE="ext4"
./install: řádek 19: devices[2]: příkaz nenalezen
3) /dev/sda6: UUID="0f9c79f2-0cb1-40a2-91d4-80d7adfe9bfd" TYPE="swap"
./install: řádek 19: devices[3]: příkaz nenalezen
4) /dev/sr0: LABEL="VOLUME IDENTIFIER" TYPE="udf"
./install: řádek 19: devices[4]: příkaz nenalezen
5) /dev/sdb: SEC_TYPE="msdos" LABEL="SMA-OP" TYPE="vfat"
Tak jsem blbý já? :) Bože - proč jsou shelly tak blbě navrženy? Tedy proč to nemůže být normální C? Nechápu význam těch machinací...
EDIT:
#!/bin/bash
Konečně! :)
Ještě k tomu výpisu dostupných DriveDevices - je na to tedy nějaký pěkný soubor v proc?
Děkuji.
-
Za prvé - na první řádek skriptu se píše interpret - když chci použít bash, napíšu tam např. #!/bin/bash
Za druhé - první řádek s interpretem je ignorován, když skript spustíš rovnou v interpretu, jak jsem ti teď napsal
Za třetí - /bin/sh vždy ukazuje na systémový shell, ve kterém jsou všechny init skripty a měnit to bude jen sebevrah. V debianích systémech je to dash.
Za čtvrtý - pokud si v systému uděláš bordel, je to tvoje věc ;)
-
v bashi (a ne v bin/sh) me to vypisuje asi tohle - coz je spravne, ze:
# ./foo.sh
1) /dev/sda1: UUID="391ae98d-666f-4202-adea-8066cd425ece" TYPE="ext3"
2) /dev/sda2: UUID="3686b597-3941-47d1-9af1-5a9485812c3a" TYPE="swap"
3) /dev/sda5: UUID="ae5f539d-d7d2-4ac2-8fa7-1d9f4bb4dfd0" TYPE="ext4"
4) /dev/sda6: UUID="660875c3-59f1-4f5a-b5ed-9f091a025d7a" TYPE="ext4"
nicmene kdybych chtel tenhle vypis, tak udelam:
# blkid | cat -n - | perl -pe 's/^\s+(\d+)\s+/$1\) /'
1) /dev/sda1: UUID="391ae98d-666f-4202-adea-8066cd425ece" TYPE="ext3"
2) /dev/sda2: UUID="3686b597-3941-47d1-9af1-5a9485812c3a" TYPE="swap"
3) /dev/sda5: UUID="ae5f539d-d7d2-4ac2-8fa7-1d9f4bb4dfd0" TYPE="ext4"
4) /dev/sda6: UUID="660875c3-59f1-4f5a-b5ed-9f091a025d7a" TYPE="ext4"
pozor .. perl -pe !!je emulace sedu, akorat se tam pise normalni RE a nemusis to vsechno escapovat jako v sedu .. neni to zadna magie, ja sed skoro nepouzivam, ale bylo by to stejny
-
Mě je samotný výpis k ničemu... Potřebuji hlavně cestu k zařízení - ostatek je pro uživatele... Pole mi stále nefunguje - sice to již nehlásí error, ale zařízení se nevybere...
while read -r line
do
number=$(($number + 1))
devices[$(($number-1))]="${line%:*}"
echo "${number}) ${line}"
done < /tmp/devices.txt
echo ">>> Select target device please (1-${number}):"
while true
do
read opt
if [[ $opt > 0 && $opt -le $number ]]
then
break
else
echo ">>> Bad input - try again..."
fi
done
device=$devices[$opt]
Navíc bych chtěl ten výpis co nejlidštější - aby i lajk mohl snadno poznat o jaké zařízení se jedná - pak jen zadá číslo a instalace proběhne sama... Ještě dodělám zápis do DVD a bude to komplet... :)
Aktuální stav:
root@sam-eME642:/mnt/Data/SMA-OP# ./install
>>> Checking for devices
1) /dev/sda1: UUID="f292a494-9f9f-471d-9e7e-d012596f17bd" TYPE="ext4"
2) /dev/sda5: UUID="4cf54643-cd1e-4547-9ea2-6058613c7fcf" TYPE="ext4"
3) /dev/sda6: UUID="0f9c79f2-0cb1-40a2-91d4-80d7adfe9bfd" TYPE="swap"
4) /dev/sr0: LABEL="VOLUME IDENTIFIER" TYPE="udf"
5) /dev/sdb: SEC_TYPE="msdos" LABEL="SMA-OP" TYPE="vfat"
>>> Select target device please (1-5):
Což mi pořád nepřijde dost lidské...
-
device=$devices[$opt] >> device=${devices[$opt]}
-
Jede to! Děkuji.
-
Tak mám ještě jeden problémec. :) Na konci instalace ještě kopíruji externí programy (které jsou již hotové, aniž bych je v průběhu instalace kompiloval) a hned po tom kopírování umountovávám cílové zařízení. Jenže to se nezdaří, jelikož kopírování ještě probíhá. Sleep použít nechci - protože to je jen tipovačka... Dalo by se zařídit vyloženě počkání na dokopírování?
Děkuji.
-
Tak nakonec jsem si to udělal sám - ale nedaří se mi dostat velikost složky v čísle - jak na to jít?
originSUR=`du -sb "${path}/done"`
targetSUR=`du -sb "${path}/tmp"`
origin="${originSUR%${path}*}"
target="${targetSUR%${path}*}"
Jenže mezery bohužel ignorovány nejsou - jak tedy do {} dostat jako pattern mezeru? Převrácené lomítko a s nefunguje. A dalo by se to osekat bez mezikroku - rovnou z ``?
Děkuji.
-
cyklus se sleepem, dokud vysledek nasledujiciho nebude nula?
lsof $umisteni | wc -l
jinak
man lsof
man wc
-
WARNING: can't stat() fuse.gvfsd-fuse file system /run/user/sam/gvfs
Output information may be incomplete.
Mám to:
while [ $origin -ge $copied ]
do
$copied=$((`lsof tmp | wc -l` - target))
pct=$((100 * $copied / $files))
echo -en ".$pct%\b\b\b"
sleep 1
done
-
path=`pwd -P`
getDirSize()
{
ret=`sudo find "${path}/${1}" -printf "%s\n" | awk '{sum+=$1} END {printf "%d\n", sum}'`
}
getDirSize done
origin=$ret
getDirSize tmp
target=$ret
copied=0
cp done/* tmp
while [ $origin > $copied ]
do
getDirSize tmp
copied=$(($ret - $target))
pct=$((100 * $copied / $origin))
echo -en ".$pct%\b\b\b"
sleep 1
done
Toto se zasekne na 0 - proč?
Děkuji.
-
Tak už jsi na to přišel?
-
Jsem schopen dostat velikost v bytech o něco snadněji, ale prostě se to zasekne...
getDirSize()
{
list=`du -sb "${path}/${1}"`
ret=`echo $list | sed -e 's/\s.*//'`
}
getDirSize "done"
origin=$ret
getDirSize "tmp"
target=$ret
copied=0
cp done/* tmp &
while [ $origin > $copied ]
do
getDirSize "tmp"
copied=$(($ret - $target))
pct=$((100 * $copied / $origin))
echo -en ".$pct%\b\b\b"
sleep 1
done
Napadá mne jen, že cyklus kopírování přeruší... Což by nastavení do pozadí podle mě mělo vyvrátit - ale neděje se nic... Respektive byty nepřibývají a tak se cyklus neukončí.
-
Podívej se jak se v bashi porovnávají čísla.
path=`pwd -P`
getDirSize()
{
ret=`du -sb "${path}/${1}"|sed 's/\s.*//'`
}
getDirSize "done"
origin=$ret
getDirSize "tmp"
target=$ret
copied=0
cp done/* tmp &
while [ $origin -gt $copied ]
do
getDirSize "tmp"
copied=$ret
pct=$((100 * $copied / $origin))
echo -en "\b\b\b.$pct%"
sleep 1
done
-
Mělo by jít i to s operandem... Každopádně to s optionem dá:
./install: řádek 121: [: -qt: očekáván binární operátor
-
Už konečně používáš Bash? Já ano a ten kód jsem testoval. Jinak stále používáš své doměnky, místo aby sis ověřoval fakta. Operátory, na které jsi zvyklý, se v Bashi používají jen na porovnávání řeťezců.
-
Kdybych nepoužíval Bash, nejela by ta část před tím... Už jsem posílal novou hlavičku souboru... Je hezké, že tobě to jde, ale mě ne... :)
path=`pwd -P`
getDirSize()
{
list=`du -sb "${path}/${1}"`
ret=`echo $list | sed -e 's/\s.*//'`
}
Neřídím se domněnkami, ale:
http://tldp.org/LDP/abs/html/comparison-ops.html
getDirSize "done"
origin=$ret
getDirSize "tmp"
target=$ret
copied=0
cp done/* tmp &
while [ $origin -qt $copied ]
do
getDirSize "tmp"
copied=$(($ret - $target))
pct=$((100 * $copied / $origin))
echo -en ".$pct%\b\b\b"
sleep 1
done
Neřídím se domněnkami, ale:
http://tldp.org/LDP/abs/html/comparison-ops.html
-
Já ale píšu o kódu, který jsem vložil já, ten tvůj jsem ani nezkoušel.
-
Joo - mám tam sice qt místo gt, ale gt mi zase stagnuje - nic se neděje - kód se zacyklí...
-
Podívej se na ten cyklus pořádně.
-
Ale to je přeci blbost - já musím anulovat dosavadní velikost cílové složky - chci dostat jen přírůstek... Jak to mám teď - zjistím si velikosti složek zdrojové a cílové. Začnu kopírovat a v cyklu se ptám na velikost cílové - velikost cílové před kopírováním...
-
Dělej si to jak chceš, mně to prostě ukazuje od nuly do sta procent a pak to skončí jak má.
-
Mě se ale prostě nezmění velikost - ta před a po je stejná... To proto se to zacyklí... Může hrát roli, že cílem je USB? Tedy namountovaný sdb do složky?
-
Rozhodně by to nemělo být důvodem zacyklení, zásadnější rozdíl je jen v tom, že usb je pomalejší a hraje daleko větší roli cache. Nejsem si teď jist, jak přesně funguje du, ale je jisté, že cp skončí dříve, než jsou data skutečně fyzicky na disku.
-
Nechal jsem cyklus běžet 5 minut - tak to už nevysvětlíš... :) Velikost se prostě za běhu scriptu nezměnila...
-
Napadlo tě zjistit si velikosti, které jsou porovnávány, jaký je konečný rozdíl? Jakou velikost má prázdný adresář?
Na mém systému:
path=`pwd -P`
getDirSize()
{
ret=`du -sb "${path}/${1}"|sed 's/\s.*//'`
}
getDirSize "done"
origin=$ret
getDirSize "tmp"
target=$(($ret-4096))
copied=0
cp done/* tmp &
while [ $origin -gt $copied ]
do
getDirSize "tmp"
copied=$(($ret-$target))
pct=$((100 * $copied / $origin))
echo -en "\b\b\b$pct%"
sleep 1
done
echo
-
Tak to mi neuvěříš... :) Já už jsem před tím testoval instalaci - ony soubory už tam byly... I tak se to zasekne na 96 procentech - tuším, že bude problém v samotné složce...
-
Já to snad nedám do kupy... :)
for f in done/*
do
if [[ $tFiles == *`basename $f`* && $all == false ]]
then
echo ">>> The target device already contains files from Done directory...";
echo ">>> Overwrite it? (all/y/n)"
read overwrite
if [ "$overwrite" = "y" ]
then
rm tmp/`basename $f`
elif [ "$overwrite" = "all" ]
then
all=true
rm tmp/`basename $f`
fi
elif [[ $tFiles == *`basename $f`* ]]
then
rm tmp/`basename $f`
else
getDirSize tmp/`basename $f`
target=$(($target - $ret))
fi
done
cp done/* tmp &
while [ $origin -gt $copied ]
do
getDirSize "tmp"
copied=$(($ret - $target))
pct=$((100 * $copied / $origin))
echo $target
echo -en ".$pct%\b\b\b"
sleep 1
done
Nyní vezmu počáteční velikost cílové složky a od ní odečítám ty soubory, které uživatel nechce smazat. Ostatní se smažou - a tak je třeba jejich velikost odečíst od target, jelikož o target pak budu snižovat velikost zkopírované části... Pak když kopíruji, tak to hodí prvně 76% a někdy 96%, ale pak už zase 0 a zacyklí se to...
-
Mně to tu už nebaví ;)
cp kopíruje všechny soubory a je jedno, zda tam už jsou, nebo ne.
Pokud tedy počítáš s tím, že tam jsou nějaké stejné soubory, přinejmenším jménem, musíš je předem smazat, nebo je vůbec nekopírovat a zohlednit to ve výpočtech. Kopírovat je přes a spoléhat se na to, že jsou stejné velikosti není zrovna moudré a rozhodně bys nemohl sledovat průběh kopírování porovnáváním velikosti před a po.
Ve smyčce musíš porovnávat relevantní data, což zahrnuje i odečtení velikosti samotného adresáře od dat, která jsou v něm uložena, protože ten rozdíl, který vypočítáš z aktuální velikosti cílového adresáře oproti původní, adresář logicky nezahrnuje.
-
Co píšeš jsem přesně udělal - shodné soubory se smažou pokud to uživatel povolí... Odečítám jen zbylé soubory...
Dále cp nepřepisuje soubory, jen s optionem f. A jde logicky o to, že když jsem vzal původní velikost a soubory se jen přepsaly (nebo vůbec nekopírovaly), tak se výsledná velikost nezměnila...
-
Takže hotovo? :)
-
Právě, že to nefunguje... Jak jsem psal - vypíše to 76%, či 96% a pak opět 0 a zacyklí se to...
-
Úloha je to dostatečně triviální, aby nebyl problém vystopovat důvod chování tvého skriptu. Co jsem sem vložil a napsal, to jsem si ověřil empiricky a všechno sedí a funguje, moje počítadla problém nemají flaška neflaška. Teď už je to na tobě.
-
Tak ta úloha zase tak triviální není... :) Už jsem našel problém - velikost souborů je sice stejná, ale užití na disku jiné. DU očividně měří velikost na disku. Jak tedy dostat velikost souborů?
-
Tak triviální, abys na tento fakt přišel do pěti minut ;)
-
Joo - du jsem nakonec použil - ale s /*, místo velikosti mateřské složky... Bůh ví, co budu dělat až tam budou subsložky... To si to rovnou napíši do bootloaderu a bude... :) Tedy abych nebyl prase, udělám to raději zvlášť... :) Každopádně děkuji.
-
du prostě počítá i s velikost adresářů, to jsem ti psal už dřív. Můžeš si hrát i s dalšími příkazy, např:
find -type f -ls | awk '{total += $7} END {print total}'
Tohle spočítá pouze regulérní soubory (rekurzivně), tedy ne symlinky, adresáře a jinou havěť ;)
Edit: jedna uvozovka mi vypadla..
-
Děkuji - na základě tvého příspěvku jsem zdokonalil svůj kód:
du -b ./* | awk '{total += $1} END {print total}'
-
Tak hlavně nezapomeň na to, že tu hvězdičku ti nahrazuje soubory shell a pokud budeš mít v adresáři jméno s mezerou, skončí to špatně ;)
-
Shell jsem si upravil pro Češtinu a tyto případy - escapuji...
Jen mám nyní opačný problém - mezitím co před tím vyšlo číslo moc malé a zacyklilo tak cyklus :o , nyní naopak vydá moc velké číslo - 127%. Přitom po použití stejných příkazů někde mimo, dosahuji správných hodnot... :)
origin=0
target=0
copied=0
tFiles=`ls tmp`
all=false
for f in done/*
do
getSize $f
origin=$(($origin + $ret))
if [[ $csys == false ]]
then
if [[ $tFiles == *`basename $f`* && $all == false ]]
then
echo ">>> The target device already contains files from Done directory...";
echo ">>> Overwrite it? (all/y/n)"
read overwrite
if [ "$overwrite" = "y" ]
then
rm tmp/`basename $f`
elif [ "$overwrite" = "all" ]
then
all=true
rm tmp/`basename $f`
else
getSize tmp/`basename $f`
target=$(($target + $ret))
fi
elif [[ $tFiles == *`basename $f`* ]]
then
rm tmp/`basename $f`
fi
fi
done
cp done/* tmp &
while [ $origin -gt $copied ]
do
copied=$((`du -bc tmp/* | tail -1 | sed -e 's/\s.*//'` - $target))
pct=$((100 * $copied / $origin))
echo -en "\r>>> Progress: ${pct}%\r"
sleep 1
done
echo ">>> Unmounting the target device..."
umount tmp
A větší problém - bez sleep se nestihne dokončit kopírování - cyklus ale skončit dříve nesmí. Proč tedy skončí?
Děkuji.
-
Pokud blbě počítáš, tak asi může skončit dřív. Pokud chceš odpojovat zařízení, měl bys počkat na sync, je tu taky cache, pokud nenamountuješ v synchroním režimu, ....