开发者

File names with spaces in BASH

I'm trying to write script that'll crop and resize large photos into HD Wallpapers.

#! /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

But it seems that the script has problems with file names having spaces (like Tumble Weed.jpg). How can I fix this?


First, you don't need ls. By using ls in backtics, you implicitly make bash parse a string into a list, which splits by whitespaces. Instead, make bash generate the list and separate it without such quirks:

Also, you need to enclose all $i usages into quotes, to make bash substitute it as a whole, not as a string split to separate words.

Here's the script that demonstrates both ideas:

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


Use read to circumvent the problem with spaces. It looks a bit unnatural to write the loop like this but it works better:

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

with -iname you also get the jpg files that might have an extension with different casing like .JPG. "i" in "iname" means ignore casing.


I would recommend to write the for-line like this:

for i in *.jpg

and encapsulate $i in double-quotes: "$i".


If you insist on the

`ls *.jpg`

style, (if you for instance get your file-names from a more complex command) you could try setting IFS to \n:

IFS='\n'

Compare these two executions:

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

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


In bash, use string replacement with find:

${string//substring/replacement}
Replace all matches of $substring with $replacement.

so this works:

find . -type f -name '*.jpg' | while read i ; do /bin/mv -f "$i" ${i// /_}; done


Use double quotes around file names. Like this:

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

Please note the double quotes around "$i".


 #! /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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜