View RSS Feed

pbojczuk

curl zamiast wget

Rating: 3 votes, 3.67 average.
Tym razem nieco bardziej pokręcony przykład pobierania pliku. W powstałym skrypcie są wady, dlatego jest to dobry materiał do krytyki. Zapraszam!

W wypadku kolejnych wydań dystrybucji SystemRescue nie ma analogicznych aliasów, by wskazywać na plik z ostatnim wydaniem tak, jak ma to miejsce w przypadku tumbleweed. Jednak SourceForge, na którym projekt SystemRescue jest utrzymywany, udostępnia łącze przekierowujące do najnowszego wydania (pliku iso), a link do docelowego serwera lustrzanego jest rozwiązywany dynamicznie.

Za pomocą curla, plik iso z najnowszym wydaniem można pobrać w ten sposób:
Code:
curl -kL https://sourceforge.net/projects/systemrescuecd/files/latest/download -o systemrescue-latest-amd64.iso
Jaki mam cel
Co kilka miesięcy, a czasem częściej, pojawia się nowe wydanie SystemRescue. Chcę mieć to wydanie dostępne lokalnie i chcę je pobrać tylko raz, gdy będzie ono już dostępne.

Jakie mam ograniczenia
Ponownie piszę w Ash. Docelowy skrypt również będzie działał na routerze z alternatywnym firmware. Również ponownie nie mogę sprawdzać sum sha256, bo nie mam na routerze dostępnej stosownej binarki. Do kompletu nie chcę męczyć procesora routera liczeniem sum kontrolnych większych plików.

Dlaczego nie wget
Posługując się curlem mogę spróbować przechwycić komunikaty przy przekierowaniach i w miarę prosty sposób zdecydować: czy iso z najnowszym wydaniem już istnieje lokalnie, czy też należy pobrać nowe.

Rozwiązywanie URL
Wymyśliłem coś takiego:
Code:
REDIRECT0="https://sourceforge.net/projects/systemrescuecd/files/latest/download"
REDIRECT1="$(curl -ks ${REDIRECT0} | grep https | sed -e 's/.*<a href="//' -e 's/">.*//')"
REDIRECT2="$(curl -ks ${REDIRECT1} | grep https | sed -e 's/.*<a href="//' -e 's/">.*//')"
Wadą tego rozwiązania jest to, że dość niezgrabnie można tutaj przechycić kod wyjścia, więc ostatecznie tego nie robię. Dodatkowo zbyt częste testowanie skryptu powoduje, że link przekierowujący nie będzie od czasu do czasu prawidłowo rozwiązywany (i bardzo dobrze!), a sam skrypt nie obsługuje takiego przypadku.

Logikę skryptu buduję wokół zawartości pliku sumy kontrolnej dla najnowszego udostępnianego obrazu iso, więc moim początkowym celem jest pobranie właśnie tegoż pliku z sumą kontrolną.

Położenie pliku z sumą kontrolną udało mi się odtworzyć, a plik pobrać w ten sposób - zwracam uwagę, że w tym wypadku curl wymaga przekierowania -L.
Code:
curl -kLs ${REDIRECT2}.sha256 -o ${TMPDIR}/${FILENAME}.sha256
case i inne zastrzeżenia
Dla przypadków takich jak poniższy zalecane jest polecenie case. Zostawiam ten kawałek skryptu dokładnie w takiej postaci po to, być mieć pod ręką inny punkt odniesienia dla analogicznych przypadków.
Code:
SOURCESHA256="$(cat ${TMPDIR}/${FILENAME}.sha256 | cut -f1 -d' ')"
grep -q ${SOURCESHA256} ${TARGETDIR}/*.sha256
RET=$?
[ ${RET} -eq 0 ] && _log "SHA256 checksum was found in ${TARGETDIR}. ${FILENAME} should be already in place." && exit 0
[ ${RET} -eq 2 ] && _log "SHA256 checksum files not found. ${TARGETDIR} appears to be empty. Continuing."
[ ${RET} -eq 1 ] && _log "SHA256 checksum not found. Continuing."
Dodatkowo nie potrafię z jednej strony zachować możliwie krótkiego i prostego kodu skryptu, a z drugiej obsłużyć wszystkich możliwch zwrotek z curla. Do kompletu nie przechwytuję też kodu wyjścia przy tworzeniu zmiennych REDIRECT.

Mimo tych wad poniższe rozwiązanie jest póki co wystarczające.

Całość skryptu
Code:
#!/bin/sh

# a script get the latest the release of SystemRescue distribution
# v0.1; 01/14/2022

SCRIPTNAME=$0
TMPDIR="/tmp/mnt/sda1/tmp"
TARGETDIR="/tmp/mnt/sda1/ftp/pub/linux/sysrescd/iso"
LOG="/tmp/mnt/sda1/var/log/$(echo ${SCRIPTNAME} | sed 's/.*\///').log"
REDIRECT0="https://sourceforge.net/projects/systemrescuecd/files/latest/download"

_log () {
        echo "$(date +"%Y%m%d.%H%M%S") :: ${SCRIPTNAME} :: $*" >> ${LOG}
}

REDIRECT1="$(curl -ks ${REDIRECT0} | grep https | sed -e 's/.*<a href="//' -e 's/">.*//')"
REDIRECT2="$(curl -ks ${REDIRECT1} | grep https | sed -e 's/.*<a href="//' -e 's/">.*//')"
FILENAME="$(echo ${REDIRECT2} | sed 's/.*\///')"

 _log "${FILENAME} to be checked."
rm -f ${TMPDIR}/${FILENAME}*

curl -kLs ${REDIRECT2}.sha256 -o ${TMPDIR}/${FILENAME}.sha256 && _log "${FILENAME}.sha256 downloaded to ${TMPDIR}."
[ ! -f ${TMPDIR}/${FILENAME}.sha256 ] && _log "Error when downloading ${FILENAME}.sha256. Exit 1." && exit 1

SOURCESHA256="$(cat ${TMPDIR}/${FILENAME}.sha256 | cut -f1 -d' ')"
grep -q ${SOURCESHA256} ${TARGETDIR}/*.sha256
RET=$?
[ ${RET} -eq 0 ] && _log "SHA256 checksum was found in ${TARGETDIR}. ${FILENAME} should be already in place." && exit 0
[ ${RET} -eq 2 ] && _log "SHA256 checksum files not found. ${TARGETDIR} appears to be empty. Continuing."
[ ${RET} -eq 1 ] && _log "SHA256 checksum not found. Continuing."

curl -ks ${REDIRECT2} -o ${TMPDIR}/${FILENAME} && _log "${FILENAME} downloaded to ${TMPDIR}."

mv ${TMPDIR}/${FILENAME}.sha256 ${TARGETDIR}/${FILENAME}.sha256
mv ${TMPDIR}/${FILENAME} ${TARGETDIR}/${FILENAME}
[ $? -eq 0 ] && _log "${FILENAME} is available locally." && exit 0

_log "End of the script reached. Exit 1" && exit 1

Submit "curl zamiast wget" to Digg Submit "curl zamiast wget" to del.icio.us Submit "curl zamiast wget" to StumbleUpon Submit "curl zamiast wget" to Google Submit "curl zamiast wget" to Facebook Submit "curl zamiast wget" to Twitter

Updated 19-Jan-2022 at 07:44 by pbojczuk

Categories
Uncategorized

Comments

  1. pbojczuk's Avatar
    Rozwiązywanie URL
    Wymyśliłem coś takiego:
    Code:
    REDIRECT0="https://sourceforge.net/projects/systemrescuecd/files/latest/download"
    REDIRECT1="$(curl -ks ${REDIRECT0} | grep https | sed -e 's/.*<a href="//' -e 's/">.*//')"
    REDIRECT2="$(curl -ks ${REDIRECT1} | grep https | sed -e 's/.*<a href="//' -e 's/">.*//')"
    Wadą tego rozwiązania jest to, że dość niezgrabnie można tutaj przechycić kod wyjścia, więc ostatecznie tego nie robię.
    No to
    Code:
    _getRedirect () {
            curl -ks $1 | grep https | sed -e 's/.*<a href="//' -e 's/">.*//'
    }
    wrzucenie curl do funkcji jest ciekawym rozwiązaniem, które może pozwolić podejść do przechwycenia kodów wyjścia z tegoż curl, Tyle, że jeżeli strona się wyświetli poprawnie, a jej zawartość się zmieni, to i tak otrzymam z curl zero na wyjściu. Natomiast poniższy test daje mi to, czego chcę: jeżeli nie znajdę oczekiwanego regexpa w nazwie pliku, oznacza to, że ponownie muszę przeanalizować zwrotkę z pierwszego przekierowania, czyli z $REDIRECT0, a sam skrypt mogę zakończyć błędem. I takie podejście wyraziłem w ten sposób:

    Code:
    REDIRECT0="https://sourceforge.net/projects/systemrescuecd/files/latest/download"
    
    _getRedirect () {
            RED="$(curl -ks $1 | grep https | sed -e 's/.*<a href=\"//' -e 's/\">.*//')"
            echo ${RED} | grep "systemrescue-.*-amd64.iso" || echo "Expected filename not recognized."
    }
    
    REDIRECT1="$(_getRedirect ${REDIRECT0})"
    REDIRECT2="$(_getRedirect ${REDIRECT1})"
    FILENAME="$(echo ${REDIRECT2} | sed 's/.*\///')"