【问题标题】:Run command with space characters in bash script在 bash 脚本中运行带有空格字符的命令
【发布时间】:2011-01-10 00:15:01
【问题描述】:

我有一个包含文件列表的文件:

02 of Clubs.eps
02 of Diamonds.eps
02 of Hearts.eps
02 of Spades.eps
...

我正在尝试将它们批量转换为多种尺寸的 png 格式。我用来执行此操作的脚本是:

while read -r line
do
    for i in 80 35 200
    do
        convert $(sed 's/ /\\ /g' <<< Cards/${line}) -size ${i}x${i} ../img/card/$(basename $(tr ' ' '_' <<< ${line} | tr '[A-Z]' '[a-z]') .eps)_${i}.png;
    done
done < card_list.txt

但是,这不起作用,显然是试图对每个单词进行拆分,导致以下错误输出:

convert: unable to open image `Cards/02\': No such file or directory @ error/blob.c/OpenBlob/2514.
convert: no decode delegate for this image format `Cards/02\' @ error/constitute.c/ReadImage/532.
convert: unable to open image `of\': No such file or directory @ error/blob.c/OpenBlob/2514.
convert: no decode delegate for this image format `of\' @ error/constitute.c/ReadImage/532.
convert: unable to open image `Clubs.eps': No such file or directory @ error/blob.c/OpenBlob/2514.

如果我将转换更改为回显,结果看起来正确,如果我复制一行并自己在 shell 中运行它,它工作正常:

convert Cards/02\ of\ Clubs.eps -size 80x80 ../img/card/02_of_clubs_80.png
convert Cards/02\ of\ Clubs.eps -size 35x35 ../img/card/02_of_clubs_35.png
convert Cards/02\ of\ Clubs.eps -size 200x200 ../img/card/02_of_clubs_200.png
convert Cards/02\ of\ Diamonds.eps -size 80x80 ../img/card/02_of_diamonds_80.png
convert Cards/02\ of\ Diamonds.eps -size 35x35 ../img/card/02_of_diamonds_35.png
convert Cards/02\ of\ Diamonds.eps -size 200x200 ../img/card/02_of_diamonds_200.png
convert Cards/02\ of\ Hearts.eps -size 80x80 ../img/card/02_of_hearts_80.png
convert Cards/02\ of\ Hearts.eps -size 35x35 ../img/card/02_of_hearts_35.png
convert Cards/02\ of\ Hearts.eps -size 200x200 ../img/card/02_of_hearts_200.png
convert Cards/02\ of\ Spades.eps -size 80x80 ../img/card/02_of_spades_80.png

更新:

只是添加引号(见下文)与上面的结果相同,我一直使用 sed 添加反斜杠

convert '"'Cards/${line}'"' -size ${i}x${i} ../img/card/$(basename $(tr ' ' '_' <<< ${line} | tr '[A-Z]' '[a-z]') .eps)_${i}.png;

双引号和单引号都试过了

【问题讨论】:

  • 我无法尝试,但我认为您需要在 $(sed ...) 上加上“”

标签: bash shell imagemagick


【解决方案1】:

Shell 可以很好地处理行拆分,并使用变量使代码可读 - 此处避免水平滚动条...

while read -r line
do
    for i in 80 35 200
    do
        epsfile="Cards/$line"
        pngbase=$(basename "$line" .eps | tr ' A-Z' '_a-z')
        pngfile="../img/card/${pngbase}_${i}.png"
        convert "$epsfile" -size ${i}x${i} "$pngfile"
    done
done < card_list.txt

如果您必须处理包含空格的文件名,则在将它们传递给命令时需要用双引号将名称括起来。将所有文件操作压缩成一行的复杂代码几乎无法阅读。您可以在一个命令中完成整个音译,如上所示,这也简化了操作。

尽管 80 个字符不是硬性限制,但还是值得将其作为一个粗略的限制,因为如果行长得多,它可能不可读,并且代码必须可读才能维护。

【讨论】:

  • 如果我没看错,pngbase 应该是从 $line 构建的,而不是 $epsfile;否则,我觉得不错。
  • @Gordon:由于basename 删除了Card/ 前缀到$epsfile,我认为这实际上并不重要,但是是的,您是正确的,原始代码可以解决这个问题的$line。我会把代码整理好。
  • @ʞɔıu:感谢您的编辑 - 抱歉,我错过了插入 PNG 文件名中的“_${i}”。
【解决方案2】:

用空格或其他特殊字符简单地引用文件名。此外,您不需要 sed 或 tr。

请参阅有关“变量替换”的 bash 文档(第 21-22 页,bash Pocket Reference,O'Reilly)

通过将转换逻辑放入函数来简化循环

# cvt file size 
cvt() {
 infile="$1"  # quote in case filename has blanks
 size="$2"
 outfile="${infile/ /_}"              # replace spaces with underlines
 outfile="${outfile##*/}"             # remove any directory path
 outfile="${outfile,,*}"              # downcase the filename
 outfile="${outfile%.eps}_$size.png"  # remove suffix, add size and new suffix
 ( set -x ; convert "Cards/$infile" -size ${size}x$size "../img/card/$outfile" )
}

while read -r line ; do
  for i in 80 35 200 ; do
    cvt "$line" $i
  done
done < card_list.txt

【讨论】:

    【解决方案3】:

    就像 Hai 说的,把你的文件名用“”括起来。否则,shell 会读取该行上的空格作为下一个参数的分隔符。

    例如。

    VAR="test file"
    cat $VAR # outputs the contents of 'test', followed by the contents of 'file'
    
    cat "$VAR" # outputs the contents of 'test file'
    

    编辑: 简而言之,您的问题是使用 sed 来逃避空格。它没有做你认为它正在做的事情——它产生的是文字字符串“02\ of\ Clubs.eps”而不是“02 of Clubs.eps”。仅将 sed 部分替换为“Cards/${line}”。

    【讨论】:

    • 您有第二个使用 $line 的实例。这也需要用“”括起来。转换 $(sed 's/ /\\ /g' 卡片/${line}) -size ${i}x${i} ../img/card/$(基本名称 $(tr ' '_' ${line} | tr '[A-Z]' '[a-z]') .eps)_${i}.png;
    • 啊,我不经常使用shell脚本。简而言之,您的问题是使用 sed 来逃避空格。它没有做你认为它正在做的事情——它产生的是文字字符串“02\ of\ Clubs.eps”而不是“02 of Clubs.eps”。将 sed 部分替换为“Cards/${line}”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-01-22
    • 2018-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多