2010-10-19 13 views
12

Sto provando a scrivere uno script che ritaglierà e ridimensionerà le foto di grandi dimensioni in sfondi HD.Nome file con spazi in BASH

#! /bin/bash 


for i in `ls *.jpg` 
do 
    width=`identify -format '%w' $i` 
    height=`identify -format '%h' $i` 

    if [ `echo "$width/$height > 16/9" | bc -l` ] 
    then 
     exec `convert $i -resize 1920 -gravity Center -crop '1920x1080+0+0' +repage temp` 
    else 
     exec `convert $i -resize x1080 -gravity Center -crop 1920x1080+0+0 +repage temp` 
    fi 

    rm $i 
    mv temp $i 
done 

Ma sembra che lo script abbia problemi con i nomi di file che hanno spazi (come Tumble Weed.jpg). Come posso risolvere questo?

+2

La risposta è già stata fornita di seguito, ma vorrei solo aggiungere che lo scripting della shell è davvero negativo per gestire gli spazi nei nomi di file perché così tanti elenchi sono delimitati da spazi, in particolare argomenti di comando. Prova ad esempio a copiare un file con spazio tramite scp! È quasi impossibile senza la fuga manuale. – Timmmm

+2

Dovresti leggere 'http: // mywiki.wooledge.org/BashPitfalls' nella sua interezza :-) migliorerà drasticamente le tue abilità di bash – Benoit

risposta

20

Innanzitutto, non è necessario ls. Utilizzando ls in backtics, si fa in modo che bash analizzi una stringa in una lista, che si divide per spazi vuoti. Invece, fai in modo che bash generi l'elenco e lo separi senza tali stranezze:

Inoltre, è necessario racchiudere tutti gli usi di $i tra virgolette, per fare in modo che bash lo sostituisca come un intero, non come una divisione di stringa per separare le parole.

Ecco lo script che dimostra entrambe le idee:

for i in *.jpg ; do 
    echo "$i"; 
done 
+0

Questo non funziona se il percorso del file contiene uno spazio bianco. Il comando sulla riga 2 (in questo caso 'echo') interpreta gli spazi come delimitatori di argomenti. – Diederik

+1

@Diederik, hm, funziona nella mia shell con gli spazi bianchi. Racchiudere '$ i' in quites fa il trucco. –

+0

Sembra che tu abbia ragione, se tutti i file si trovano nella stessa directory questo funzionerà anche con gli spazi. Il mio script ha fallito con spazi quando ho usato 'find' con un ciclo for. Lo spazio nel nome della cartella ha fatto scattare il mio script. – Diederik

0

Utilizzare le virgolette doppie attorno ai nomi di file. In questo modo:

width=`identify -format '%w' "$i"` 

Si prega di notare le doppie virgolette intorno a "$i".

4

mi sento di raccomandare a scrivere il per-linea come questa:

for i in *.jpg 

e incapsulare $i fra virgolette: "$i".


Se si insiste sullo stile

`ls *.jpg` 

, (se per esempio ottenere i vostri nomi dei file da un comando più complesso) si potrebbe provare a impostare IFS a \n:

IFS='\n' 

Confrontare queste due esecuzioni:

$ for f in `ls *`; do echo $f; done 
hello 
world 
test 

$ IFS='\n'; for f in `ls *`; do echo $f; done 
hello world 
test 
14

Usa lettura per aggirare il problema con gli spazi. Sembra un po 'innaturale per scrivere il ciclo come questo, ma funziona meglio:

find . -type f -iname "*.jpg" | while read i 
do 
    # your original code inside the loop using "$i" instead of $i 
done 

con -iname si ottiene anche i file jpg che potrebbero avere un'estensione con rivestimento diverso, come .JPG. "i" in "iname" significa ignorare l'involucro.

+0

Così com'è, questo fallisce con i nomi con letterali backslash, nomi con newline letterali e nomi termina in spazi bianchi. –

+0

Per risolvere il problema, aggiungi un '-print0' a' find', e rendi lo shell end 'mentre IFS = read -r -d' 'i'; il '-r' corregge i backslash,' -d '' 'e' -print0' risolvono le newline letterali, e 'IFS =' corregge il supporto per i nomi che terminano in spazi bianchi. –

0
#! /bin/bash 
mkfifo ./lsOutput 
ls -1 *.jpg > ./lsOutput 
    while read line 
    do 

    width=`identify -format '%w' "$line"` 
    height=`identify -format '%h' "$line"` 

    if [ `echo "$width/$height > 16/9" | bc -l` ] 
    then 
     exec `convert "$line" -resize 1920 -gravity Center -crop '1920x1080+0+0' +repage temp` 
    else 
     exec `convert "$line" -resize x1080 -gravity Center -crop 1920x1080+0+0 +repage temp` 
    fi 

    rm "$line" 
    mv temp "$line" 
done<./lsOutput 
1

in bash, l'uso di sostituzione stringa con trovare

$ {stringa // sottostringa/sostituto}

Replace all matches of $substring with $replacement. 

quindi questo funziona:

trovare. -tipo f -name '*.jpg '| mentre leggi i; do/bin/mv -f "$ i" $ {i ///_}; done

Problemi correlati