Ugyan megoldottam a gondomat, de érdekel az, hogy miért nem működött egy korábbi script változatom. A picike scriptem annyit csinál, hogy ssh-n keresztül felmásol a router-em RAM-jába file-okat. Az rsync nem jó, mert nincs elég hely ahhoz, hogy a router-re feltegyem az rsync-et. A lényeg, hogy szimbolikus linket is kell másolni. A program rekurzívan bejárja az alkönyvtárakat. Ez a változat működik:
#!/bin/bash
BASE='/tmp'
copy() {
unset list
i=0
while read -r; do
list[i++]="$REPLY"
done < <(ls -1)
lenlist=$i
i=0
while [ $i -lt $lenlist ]; do
file="${list[i++]}"
len=${#file}
if cd "$file" &>/dev/null; then
ssh locsemege@router "
cd \"$BASE/$dir\"
mkdir \"$file\"
"
dir+="/$file"
(copy)
dir="${dir%/*}"
cd ..
continue
fi
if [ -h "$file" ]; then
ssh locsemege@router "
cd \"$BASE/$dir\"
ln -s \"`readlink $file`\" \"$file\"
"
continue
fi
if [ "${file:len-1}" != '~' ]; then
scp -C "$file" locsemege@router:"$BASE/$dir/$file"
fi
done
}
ssh locsemege@router 'rm -Rf /tmp/www; mkdir /tmp/www'
dir='www'
cd /home/locsemege/router/www
copy
A gondom az, hogy amennyiben nem másoltam az aktuális file listát egy tömbbe, hanem akár pipe-oltam
ls -1 | while read -r; do
...
done
akár process helyettesítést használtam
while read -r; do
...
done < <(ls -1)
akár a file listát irányítottam a ciklusba
list="`ls -1`"
while read -r; do
...
done <<<"$list"
az történt, hogy amikor a legmélyebb ciklusból visszatért a copy függvény, az őt hívó ciklusból is azonnal kilépett. Debugoltam, az utóbbi esetben a file lista nem sérült, a visszatérés után megvolt. Pedig a rekurzív hívást gömbölyded zárójelbe írva subshellben teszem: (copy). A változók ennek megfelelően nem is íródnak felül, a jelenlegi programverzió működik.
Az a gyanúm, az átírányításkor lehet valami olyasmi, hogy a rekurzión belül a file descriptorok esetében nincs mentés, vagy nem tudom, lényeg, hogy ha a belső read visszatér EOF-fal, a külső, hívó ciklus is azonnal visszatér, tehát hiába vannak még a listának feldolgozatlan elemei a read EOF-fal tér vissza. Pedig nem szeretném. Azt nem mondom, hogy nem kéne, mert nyilván én nem tudok valamit.
Az utolsó feltételben azért vizsgálom a filenév utolsó karaktereként a tilde jelet, mert az editor által létrehozott backup file-okat nem szeretném a router-re másolni.
Miért nem működtek a triviális programváltozataim, miért kellett egy tömbből feldolgoznom a listaelemeket rekurzív hívás esetén, miért nem működött az átirányítás?
- 1377 megtekintés
Hozzászólások
hol van Zahy, hogy megmondja a frankót?
- A hozzászóláshoz be kell jelentkezni
Dógozik, de szerencsére mire megtalálja a szálat, az megoldódik magadtól.
=====
tl;dr
Egy-két mondatban leírnátok, hogy lehet ellopni egy bitcoin-t?
- A hozzászóláshoz be kell jelentkezni
Illetve magamtól. ;)
Szerk.: Mondjuk nem először szívom meg ezt. Valaha az ffmpeg-gel próbáltam ciklusban file-okat feldolgozni, de az is elette az stdin-t a read elől. Ezek ilyen falánk programok. :)
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
(Mellesleg meg mernék esküdni, hogy ugyanez volt már itt is k.anyázási téma . baromira ismerős, noha fejből nem emlékszem az ssh ilyetén hülyeségére. Mondjuk mivel én elég sokszor úgy debuggolok, hogy a fizikailag izgalmas parancs elé írok egy echo-t, elég hamar ki kellett volna derülnie, hisz az echo nem zabálja fel az stdin-t.)
=====
tl;dr
Egy-két mondatban leírnátok, hogy lehet ellopni egy bitcoin-t?
- A hozzászóláshoz be kell jelentkezni
Talán épp én nyafoghattam ezen, csak hát nem tanulok a saját hibámból. :( Az ffmpeg csinálta ugyanezt. Debugoltam én, annyit láttam, hogy nem íródik felül a lista, meg annyit is, hogy nem a continue a bűnös, mert átírtam if ... ; then ... elif ...; then ... fi alakúra is, ugyanez volt a baj. Az ssh-ra meg nem gyanakodtam, pedig logikus, hiszen ssh-val lehet távolban programot futtatni, amit innen lehet pipe-ról etetni. Másra gondoltam, így az általad említett echo-t, ami kommentet csinált volna az ssh-ból, nem alkalmaztam. Arra tippeltem, a rekurzió miatt összekuszálódnak a file leírók, vagy nem tudom.
Azért gyakorlati haszna is volt ennek a topic-nak. Valamiért a kézenfekvő tar nem jutott eszembe, de javasolták, s ezen ajánlás alapján lett egy 3 soros, lényegesen gyorsabban futó script belőle. :)
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
tar-ral nem lett volna egyszerűbb (az szokott lenni a routereken)?
cd /home/locsemege/router/www
tar czf - * | ssh locsemege@router 'rm -Rf /tmp/www; mkdir /tmp/www;cd /tmp/www;tar xvzf -'
- A hozzászóláshoz be kell jelentkezni
De, csak nem jutott eszembe! :) Na jó, ez a gyakorlati része. Meg az, hogy a scriptem is működik. Viszont érdekel továbbra is, hogy miért nem működött a rekurzió, ha a rekurzív hívás abban a ciklusban van, amelyik a beleírányított listát dolgozza épp fel, miközben a hívás subshellben történik.
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Köszönöm a kézenfekvő tippet, ha már voltam olyan ügyetlen, hogy a nyilvánvaló nem jutott eszembe. :D Ez lett belőle:
#!/bin/bash
cd /home/locsemege/router
tar --exclude-backups -czf - www | ssh locsemege@router 'rm -Rf /tmp/www; cd /tmp; tar -xzf -'
cd -
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
#!/bin/bash
i=1
copy() {
echo "ok - $i"
i=$[$i+1]
copy # nézd meg zárójelesen, (copy)-val is
}
copy
Nézd meg mindkét esetben egy másik terminálban, hány procesz fog keletkezni. Biztosan zárójellel akartad?
- A hozzászóláshoz be kell jelentkezni
Amit te írtál, így egy fork bomba, már feltéve, hogy ott a zárójel. Ha nincs ott a zárójel, úgy csak egy sima memory leak. :) Mert néha vissza is kellene térni. Nekem épp azért kellett a subshell, hogy ne az éppen aktuális változóim íródjanak felül, hanem egy új memóriaterületen legyen foglalva az újabb copy hívás változóterülete. Ez épp azért kell, hogy visszatérés után a hívó copy ott folytathassa, ahol abbahagyta.
A scriptem működik jól. Nem ezzel van a bajom, hanem azzal, hogy amennyiben átirányításon belül - legyen az pipe, process substitution, vagy here string - történik a rekurzív hívás, úgy visszatérés után a hívó függvény is visszatér, nem dolgozza fel a lista még fennmaradó elemeit. Tehát vagy ugyanazt a memóriát használják átirányításkor, vagy a subshellben nem keletkezik valamiféle másodpéldány abból a változóból, amely a read EOF státuszát tárolja, vagy valami ilyesmi. Ehhez kellene például egy hozzáértő Zahy. ;)
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Diszkléjmer-féle: éppen dögrováson vagyok, kód szárazfuttatása ellen minden sejtem tiltakozik, de valami azért feltűnt: írod, hogy a változóidat védenéd, de nem látok egy local deklarációkat. Van ennek oka?
- A hozzászóláshoz be kell jelentkezni
Már a hülyeségemen kívül? :) Semmi. Igazad van, akkor még a subshell is elhagyható lenne, ha jól látom, ez javítana a memóriahasználaton és a futásidőn is. Nem, mintha ebben a felhasználásban ezek annyira hatalmasak lettek volna.
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
" Nekem épp azért kellett a subshell, hogy ne az éppen aktuális változóim íródjanak felül, hanem egy új memóriaterületen legyen foglalva az újabb copy hívás változóterülete."
Bash-ben lehet lokális változókat a
local
parancs segítségével.
- A hozzászóláshoz be kell jelentkezni
Különben valamit nyilván csúnyán benézek, mert ez meg működik:
#!/bin/bash
copy() {
echo '>'
while read -r; do
if cd "$REPLY" &>/dev/null; then
pwd
(copy)
cd ..
continue
fi
echo "$REPLY"
done < <(ls -1)
echo '<'
}
cd /home/locsemege/router/www
copy
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Anélkül, hogy pontosan tudnám, mi a baj, van egy tippem. Csak az, amit sokadjára szívok meg. A ciklusmagban valami - itt vélhetően az ssh - megeszi a standard inputot, így aztán mire a read-re kerül a sor, már nincs feldolgozandó elem.
Azt hiszem, egy ssh -n megoldotta volna a gondomat.
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Igen, ez volt a baj, teszteltem. A ciklusmagban az ssh felzabálta az stdin-t, amelyet én valójában a while-ban lévő read-nek szántam. A megoldás az ssh parancs -n kapcsolója:
-n Redirects stdin from /dev/null (actually, prevents reading from
stdin). This must be used when ssh is run in the background. A
common trick is to use this to run X11 programs on a remote
machine. For example, ssh -n shadows.cs.hut.fi emacs & will
start an emacs on shadows.cs.hut.fi, and the X11 connection will
be automatically forwarded over an encrypted channel. The ssh
program will be put in the background. (This does not work if
ssh needs to ask for a password or passphrase; see also the -f
option.)
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Köszi a témát, tanulságos.
- A hozzászóláshoz be kell jelentkezni
haha, ezzel en is megszivtam mar. child processz orokli az stdin-t. Azota nagyon ovatos vagyok az stdin-rol taplalkozo while-okkal, read-ekkel.
- A hozzászóláshoz be kell jelentkezni
Hali, sajnos most épp nem vagyok hibakeresős üzemmódban, de elsőre az 'unset list' helyett 'local list; declare -a list'-et próbálnék
- A hozzászóláshoz be kell jelentkezni
Köszönöm, de már megtaláltam a baj forrását. Az stdin-t falta fel az ssh a read elől.
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni