Bij het downloaden, kopiëren, verplaatsen of bewerken worden bestanden soms beschadigd. Zo gebruik ik een script om dagelijks een andere bureaublad achtergrond te downloaden. Heel af en toe gebeurde het dat er een foutmelding i.p.v. een JPEG afbeelding werd gedownload. De hoogste tijd om na het downloaden de JPEG afbeelding te testen.
Een test waarbij je enkel controleert of een JPEG bestand de extensie .jpg heeft is geen zekerheid dat je met een geldige JPEG afbeelding hebt te maken.
De opdracht file
achterhaald het formaat van een bestand.
Een paar voorbeelden:
dany@pindabook:~>file Documenten/Systeembeheer/wallpaper.sh
Documenten/Systeembeheer/wallpaper.sh: Bourne-Again shell script, UTF-8 Unicode text executable dany@pindabook:~>file Afbeeldingen/Achtergronden/02822_daisy_1920x1080.jpg
Afbeeldingen/Achtergronden/02822_daisy_1920x1080.jpg: JPEG image data, JFIF standard 1.02, aspect ratio, density 100x100, segment length 16, progressive, precision 8, 1920x1080, frames 3 dany@pindabook:~>file Afbeeldingen/Achtergronden/03104_tekapodawn_1920x1080.jpg
Afbeeldingen/Achtergronden/03104_tekapodawn_1920x1080.jpg: HTML document, ASCII text, with very long lines, with CRLF, CR, LF line terminators
Bij de eerste opdracht wordt het bestand wallpaper.sh geïdentificeerd als een Bourne-Again shell script. Bij de tweede opdracht identificeert file het bestand 02822_daisy_1920x1080.jpg als een JPEG image. Bij de laatste opdracht wordt een schijnbaar JPG-bestand als HTML document geïdentificeerd. Dit JPG bestand werd gedownload, maar door een fout werd i.p.v. een JPG afbeelding een foutmelding in het HTML formaat doorgestuurd.
Door gebruik te maken van jokertekens en filteropdrachten kan je snel volledige mappen doorzoeken. Om alle JPG bestanden (*.jpg) in een map (Afbeeldingen/Achtergronden) te identificeren met de file opdracht:
dany@pindabook:~> file Afbeeldingen/Achtergronden/*.jpg | grep -v "JPEG image data"
Afbeeldingen/Achtergronden/03104_tekapodawn_1920x1080.jpg: HTML document, ASCII text, with very long lines, with CRLF, CR, LF line terminators
De file opdracht identificeert alle JPG bestanden en de grep opdracht filtert er alle regels uit die de woorden "JPEG image data" niet (-v) bevatten en dus niet als JPG bestand geïdentificeerd werden.
Om op de gevonden resultaten een bewerking uit te voeren, gebruik je een lus met opdrachten die op elk gevonden resultaat uitgevoerd worden. Om enkel het pad en de bestandsnaam weer te geven, wordt de opdracht:
dany@pindabook:~> file Afbeeldingen/Achtergronden/*.jpg | grep -v "JPEG image data" | while read line ; do echo "${line%%:*}" ; done
Afbeeldingen/Achtergronden/03104_tekapodawn_1920x1080.jpg
Het pad en de bestandnaam worden uit de regel gefilterd door gebruik te maken van tekenreeksbewerkingen (string manipulation) in Bash. De constructie ${line%%:*} verwijdert uit de tekenreeks line de langste tekenreeks te beginnen vanaf het einde (%%) die bestaat uit een dubbel punt gevolgd door om het even wat (:*).
De opdracht wordt een stuk duidelijker als we deze op verschillende regels plaatsen:
dany@pindabook:~>file Afbeeldingen/Achtergronden/*.jpg | grep -v "JPEG image data" | while read line
>do
>echo "${line%%:*}"
>done
Afbeeldingen/Achtergronden/03104_tekapodawn_1920x1080.jpg
Als de opdrachtregel te complex wordt, wordt het tijd om uw opdrachten in een script te plaatsen. Zo kan je dit uitbreiden om de niet als JPEG geïdentificeerde bestanden naar een map te verplaatsen of nog drastischer te verwijderen.
De file opdracht identificeert bijna alle bestandsformaten, maar is geen JPEG specialist. De opdracht identify is dat wel. Deze opdracht controleert JPEG bestanden op fouten. M.a.w. als identify zijn fiat geeft, mag je zeker zijn dat het om een geldige JPEG afbeelding gaat. Dezelfde testvoorbeelden, maar nu met identify:
dany@pindabook:~>identify Documenten/Systeembeheer/wallpaper.sh
identify: no decode delegate for this image format `SH' @ error/constitute.c/ReadImage/512. dany@pindabook:~>identify Afbeeldingen/Achtergronden/02822_daisy_1920x1080.jpg
Afbeeldingen/Achtergronden/02822_daisy_1920x1080.jpg JPEG 1920x1080 1920x1080+0+0 8-bit sRGB 1.04908MiB 0.000u 0:00.009 dany@pindabook:~>identify Afbeeldingen/Achtergronden/03104_tekapodawn_1920x1080.jpg
identify: Not a JPEG file: starts with 0x0a 0x3c `Afbeeldingen/Achtergronden/03104_tekapodawn_1920x1080.jpg' @ error/jpeg.c/JPEGErrorHandler/332.
Enkel de tweede opdracht geeft geen foutmelding en is dus een geldige JPEG afbeelding. Daar identify een onderdeel is van het imageMagick pakket, zullen alle door imageMagick ondersteunde afbeeldingsformaten geen foutmeldingen opleveren. M.a.w. identify controleert allerlei afbeeldingsformaten op fouten.
Als je in een map enkel de ongeldige JPEG bestanden wilt weergeven:
dany@pindabook:~> identify Afbeeldingen/Achtergronden/*.jpg 2>&1 >/dev/null
identify: Not a JPEG file: starts with 0x0a 0x3c `Afbeeldingen/Achtergronden/03104_tekapodawn_1920x1080.jpg' @ error/jpeg.c/JPEGErrorHandler/332.
De identify opdracht (zoals zoveel opdrachten) heeft twee soorten uitvoer (meldingen). Standaard uitvoer om standaard meldingen weer te geven en fout uitvoer om foutmeldingen weer te geven. Met de constructie 2>&1 sturen we de foutmeldingen (2) naar de standaard uitvoer (1), de oorspronkelijke standaarduitvoer wordt naar een zwart gat gestuurd (>/dev/null) waardoor enkel nog de foutmeldingen worden weergegeven. Door gebruik te maken van een while lus kunnen we op de ongeldige JPEG bestanden opdrachten loslaten:
dany@pindabook:~>identify Afbeeldingen/Achtergronden/*.jpg 2>&1 >/dev/null | while read line
>do
>echo "$line" | cut -d'`' -f2 | cut -d"'" -f1
>done
Afbeeldingen/Achtergronden/03104_tekapodawn_1920x1080.jpg
De eerste cut opdracht splits de tekenreeks op het backtick teken (`) en behoudt het tweede stuk (-f2). De tweede cut opdracht splits de tekenreeks op het teken ' en behoudt het eerste stuk (-f1). Bij de eerste cut opdracht bakenen we het splitsteken af met behulp van enkele aanhalingstekens en bij het tweede met dubbele, dit om verwarring met de splitstekens zelf te vermijden.
Met het volgende script wordt er per dag indien mogelijk een nieuwe achtergrond via het internet opgehaald. Er worden maximaal 100 achtergronden bewaard. Uit deze 100 achtergronden wordt bij elke systeemstart één willekeurige achtergrond geselecteerd en opgeslagen als ~/Afbeeldingen/Achtergrond.jpg. Als je dit script dus bij elke systeemstart laat uitvoeren en je als Bureaublad-achtergrond de afbeelding ~/Afbeeldingen/Achtergrond.jpg gebruikt, krijg je het gewenste effect.
#!/bin/bash # Wacht tot de grafische opgeving volledig is opgestart sleep 1m # Maak indien nodig een verborgen map voor pinda instellingen aan if [ ! -d $HOME/.pinda ]; then mkdir -p $HOME/.pinda touch $HOME/.pinda/wallpaper fi # Willekeurige oude achtergrond achtergrond=`ls /usr/home/Documents/Afbeeldingen/Achtergronden/*.jpg |sort -R |tail -1` # Haal per dag één nieuwe achtergrond op, filemtime=`stat -c %Y $HOME/.pinda/wallpaper` currtime=`date +%s` if [ $((currtime - filemtime)) -gt 43200 ]; then # Set InterfaceLift specifics SITE=interfacelift.com PAGE=https://$SITE/wallpaper/downloads/random/wide_16:9/1920x1080/index.html #echo $PAGE # Wacht tot het netwerk opgestart is. while ! ping -c 1 $SITE; do sleep 1m done # check if InterfaceLift is reachable if curl -s --head --request GET https://$SITE ; then # Hou enkel de 100 recenste achtergronden numfiles=($HOME/Afbeeldingen/Achtergronden/*) numfiles=${#numfiles[@]} while [ $((numfiles)) -gt 99 ]; do unset -v oldest for file in $HOME/Afbeeldingen/Achtergronden/*; do [[ -z $oldest || $file -ot $oldest ]] && oldest=$file done rm $oldest numfiles=($HOME/Afbeeldingen/Achtergronden/*) numfiles=${#numfiles[@]} done # Eén nieuwe achtergrond per dag ophalen touch $HOME/.pinda/wallpaper # extract wallpaper of the day url WOTD=`wget --user-agent="Mozilla/5.0 (X11; Linux x86_64; rv:49.0) Gecko/20100101 Firefox/49.0" -qO - $PAGE | grep "click here to download" | head -1 | sed -e "s,.*href=\",," -e "s,\",," | cut -d '>' -f 1` #echo $WOTD # wget --user-agent="Mozilla/5.0 (X11; Linux x86_64; rv:49.0) Gecko/20100101 Firefox/49.0" --directory-prefix=$HOME/Afbeeldingen/Achtergronden/ https://$SITE$WOTD wget --user-agent="Mozilla/5.0 (X11; Linux x86_64; rv:49.0) Gecko/20100101 Firefox/49.0" --output-document=$HOME/Afbeeldingen/Achtergronden/$(basename $WOTD) https://$SITE$WOTD # Nieuwe achtergrond achtergrond=$HOME/Afbeeldingen/Achtergronden/$(basename $WOTD) kdialog --title "$titel" --passivepopup "Nieuwe achtergrond opgehaald." 5 elif curl -s --head --request GET https://wallpaperscraft.com ; then PICURLPAGE=`wget -qO - https://wallpaperscraft.com/all/1920x1080 | awk '/wallpaper_pre/{getline; print}' | head -1 | sed -e "s,.*href=\",," -e "s,\",," | cut -d ' ' -f 1` PICURL=`wget -qO - https:$PICURLPAGE | grep "1920x1080.jpg" | head -1 | sed -e "s,.*src=\",," -e "s,\",," | cut -d ' ' -f 1` wget -O $HOME/Afbeeldingen/Achtergronden/$(basename $PICURL) https:$PICURL achtergrond=$HOME/Afbeeldingen/Achtergronden/$(basename $PICURL) kdialog --title "$titel" --passivepopup "Nieuwe achtergrond opgehaald." 5 fi fi titel="Ophalen achtergrondafbeelding" if file "$achtergrond" | grep 'JPEG image data' ; then cp "$achtergrond" $HOME/Afbeeldingen/Achtergrond.jpg else rm "$achtergrond" kdialog --title "$titel" --passivepopup "De opgehaalde achtergrond was geen JPEG afbeelding." 5 fi
Sla dit script op (bijvoorbeeld als ~/Documenten/Systeembeheer/wallpaper.sh) en maak het met de volgende opdracht uitvoerbaar:
dany@pindabook:~> chmod +x Documenten/Systeembeheer/wallpaper.sh
Test het script grondig in de terminal voor je het bij elke systeemstart laat uitvoeren. Door de sleep opdracht, wordt het script pas echt gestart na 1 minuut. Deze wachttijd zorgt ervoor dat het systeem volledig is opgestart voor het script zijn werk doet.
dany@pindabook:~> Documenten/Systeembeheer/wallpaper.sh
/usr/home/Documents/Afbeeldingen/Achtergronden/03749_deepblue_1920x1080.jpg: JPEG image data, Exif standard: [TIFF image data, big-endian, direntries=16, height=2750, bps=0, compression=LZW, PhotometricIntepretation=RGB, manufacturer=SAMSUNG, model=NX10, orientation=upper-left, width=4400], progressive, precision 8, 1920x1080, frames 3
Daarna kan je via de Systeeminstellingen van KDE in de rubriek Opstarten en afsluiten in het onderdeel Autostart het script toevoegen om het bij elke systeemstart te laten uitvoeren.