BASH dirname basename 有空格的问题

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29505788/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 12:44:53  来源:igfitidea点击:

BASH dirname basename problems with spaces

bash

提问by jmituzas

Writing a script to optimize my images for the web. Having issues with filenames and directories with spaces in the names.

编写脚本来优化我的网络图像。文件名和名称中带有空格的目录有问题。

Heres what I have:

这是我所拥有的:

read -p "Enter full path from root (/) to your site... example /var/www/public_html: " path1
echo ""
#read -p "Enter in ImageMagick quality (default is 80) if unsure enter 80: " optjpg
#echo ""
#id="$(id -u optiimage)"
cmd="id -u optiimage"
eval $cmd
id=$(eval $cmd)
tmp1="${path1}/shell/optiimage/imagemagick"
tmp2="${path1}/shell/optiimage/imagemagick/jpg"
restore1="${path1}/shell/optiimage/restore"
restore2="${path1}/shell/optiimage/restore/imagemagick/jpg"
backup1="${path1}/shell/optiimage/backup"
backup2="${path1}/shell/optiimage/backup/imagemagick/jpg"
log1="${path1}/shell/optiimage/log/imagemagick/"
DATE="$(date +%a-%b-%y-%T)"
# Need user input for www path from root
##
## Make directories
##
############################################################################################################
mkdir -p ${tmp1}
mkdir -p ${tmp2}
mkdir -p ${restore1}
mkdir -p ${restore2}
mkdir -p ${backup1}
mkdir -p ${backup2}
mkdir -p ${log1}
mkdir -p ${path1}/build

    echo "Processing JPG Files"
    find $path1 -iname "*jpg" | \
    #write out script to put on cron for image optimization
while read file;
do
    # If not equal to optimage uid
    # to check username id -u optimage
    if [ -u "${id}" ]; then
        filebase=`basename "$file" .jpg`
        dirbase=`dirname "$file"`
        echo "${dirbase}/${filebase}.jpg already optimized" >> ${log1}_optimized_$DATE.log
    else
    #simple log for size of image before optimization
    ls -s $file >> ${log1}_before_$DATE.log
    #Do the following if *.jpg found
        filebase=`basename $file .jpg`
        dirbase=`dirname $file`
        echo "cp -p ${dirbase}/${filebase}.jpg ${tmp2}" >> ${path1}/build/backup_jpg.txt
        echo "chown optiimage:www-data ${filebase}.jpg" >> ${path1}/build/restore_jpg.txt #${restore1}/imagemagick.sh
        echo "cp -p ${filebase}.jpg ${dirbase}/${filebase}.jpg" >> ${path1}/build/restore_jpg.txt #${restore1}/imagemagick.sh
    ##
    ## ImageMagick
    ## Original Command:
    ## convert $file -quality 80 ${filebase}.new.jpg
    ##########################
        echo "convert ${dirbase}/${filebase}.jpg -quality 80 ${tmp2}/${filebase}.jpg" >> ${path1}/build/imagemagick.txt 
        echo "mogrify -strip ${tmp2}/${filebase}.jpg" >> ${path1}/build/imagemagick.txt
        echo "chown optiimage:www-data ${tmp2}/${filebase}.jpg" >> ${path1}/build/owner_jpg.txt
        echo "rm ${dirbase}/${filebase}.jpg" >> ${path1}/build/remove_jpg.txt
        echo "cp -p ${tmp2}/${filebase}.jpg ${dirbase}/" >> ${path1}/build/migrate_jpg.txt

simple log for size of image after optimization

优化后图像大小的简单日志

     ls -s $file >> ${log1}_after_$DATE.log
    fi
done

I have edited this with suggestions some have given me. It didn't seem to work. This works fine if I remove directories with spaces in the names otherwise it ends the name at the space and get errors directory doesn't exist.

我根据一些人给我的建议对其进行了编辑。它似乎不起作用。如果我删除名称中带有空格的目录,这会正常工作,否则它会在空格处结束名称并获取错误目录不存在。

回答by bgoldst

  1. You need to double-quote variable substitutions. This applies inside command substitutions as well as in the top-level lexical context. The only exception to this is assignment of a string variable from another string variable, e.g. str2=$str1;, although other types of variable assignments generally need quoting, such as assigning a string variable from an array slice, even if it only slices one element, e.g. str="${@:1:1}";.
  2. Although unlikely to be a problem here, the readbuiltin strips leading and trailing whitespace if you provide one or more NAMEs; you can solve that by not providing any NAMEs at all, and just letting it store the whole line in the $REPLYvariable by default.
  3. You should always use the -roption of the readbuiltin, as that prevents its ill-advised default behavior of doing backslash interpolation/removal on the input data.
  4. If you don't need any kind of interpolation in a string literal, prefer the '...'syntax to "...", as the former does not do any interpolation.
  5. Prefer the [[ ... ]]expression evaluation form to the old-style [ ... ]form, as the former syntax is slightly more powerful.
  6. Prefer the $(...)command substitution form to the old-style `...`form, as the former syntax has more favorable nesting properties (namely, no need to escape the nested command substitution delimiters).
  1. 您需要双引号变量替换。这适用于内部命令替换以及顶级词汇上下文。唯一的例外是从另一个字符串变量分配字符串变量,例如str2=$str1;,尽管其他类型的变量分配通常需要引用,例如从数组切片分配字符串变量,即使它只对一个元素进行切片,例如str="${@:1:1}";
  2. 虽然在这里不太可能成为问题,但read如果您提供一个或多个NAMEs ,则内置会删除前导和尾随空格;您可以通过根本不提供任何NAMEs来解决这个问题,而只是让它$REPLY默认将整行存储在变量中。
  3. 您应该始终使用内置-r选项read,因为这可以防止其对输入数据进行反斜杠插值/删除的不明智的默认行为。
  4. 如果您不需要在字符串文字中进行任何类型的插值,则更喜欢使用'...'语法"...",因为前者不进行任何插值。
  5. [[ ... ]]与旧式[ ... ]形式相比,更喜欢表达式求值形式,因为前者的语法稍微强大一些。
  6. 更喜欢$(...)命令替换形式而不是旧式`...`形式,因为前者的语法具有更有利的嵌套属性(即,无需转义嵌套的命令替换分隔符)。


find "$path1" -iname '*jpeg'| \
    # write out script to put on cron for image optimization
    while read -r; do
        file=$REPLY;
        # If not equal to optimage uid
        # to check username id -u optimage
        if [[ -u "$id" ]]; then
            filebase=$(basename "$file" .jpeg);
            dirbase=$(dirname "$file");
            #MYBASENAME=$(basename "")
            echo "${dirbase}/${filebase}.jpeg already optimized" >>"${log1}_optimized_$DATE.log";
        fi;
    done;
;

回答by higuaro

Quote your $filevariable in every place where is used:

$file在每个使用的地方引用你的变量:

find $path1 -iname "*jpeg" | \
    while read file;
    do
        if [ -u "${id}" ]; then
            filebase=`basename "$file" .jpeg`
            dirbase=`dirname "$file"`
        fi
    done