【问题标题】:Filter Hidden Files with Bash (for Batch Image Resize Script)使用 Bash 过滤隐藏文件(用于批量图像调整脚本)
【发布时间】:2009-11-16 07:59:12
【问题描述】:

我正在编写一个脚本来批量调整图像大小。最初我正在应用一个操作for file in $(ls $1),但我希望能够使用通配符,所以我正在寻找更像for file in $(echo $1) 的东西。问题是 dotglob 可能会也可能不会启用,因此echo * 可能会返回隐藏文件(特别是 .DS_Store),这会导致convert 抛出错误并停止脚本。 我希望命令的默认行为是,如果我将cd 放入一个充满图像的目录并执行resize * 400x400 jpg,则所有图像都将调整大小不包括 隐藏文件,无论是否启用 dotglob。

所以,在伪代码中,我正在寻找

for file in $(echo $1 | [filter-hidden-files])

这是我的旧行为脚本。当我找到解决方案时将更新新行为:

# !/bin/bash

# resize [folder] [sizeXxsizeY] [outputformat]
# if [outputformat] is omitted, the input file format is assumed

for file in $(ls $1)
do
    IMGNAME=$(echo "$file" | cut -d'.' -f1)
    if test -z $3
    then
        EXTENSION=$(echo "$file" | cut -d'.' -f2)
        convert $1/$file -resize $2 -quality 100 $1/$IMGNAME-$2.$EXTENSION
        echo "$file => $IMGNAME-$2.$EXTENSION"
    else 
        convert $1/$file -resize $2 -quality 100 $1/$IMGNAME-$2.$3
        echo "$file => $IMGNAME-$2.$3"
    fi
done

这是当前脚本:

# !/bin/bash

# resize [pattern] [sizeXxsizeY] [outputformat]
# if [outputformat] is omitted, the input file format is assumed

for file in $(echo $1)
do
        IMGNAME=$(echo "$file" | cut -d'.' -f1)
        if test -z $3 && if test -f $3
        then
            EXTENSION=$(echo "$file" | cut -d'.' -f2)
            convert $file -resize $2 -quality 100 $IMGNAME-$2.$EXTENSION
            echo "$file => $IMGNAME-$2.$EXTENSION"
        else 
            convert $file -resize $2 -quality 100 $IMGNAME-$2.$3
            echo "$file => $IMGNAME-$2.$3"
        fi
done

给定命令resize * 400x400,convert 会抛出错误,因为它无法处理 .DS_Store(位于 OSX 系统上每个文件中的隐藏文件)。因为我永远不会处理隐藏的图像,所以我想自动过滤它们。我一直在尝试使用 grep 或 find 来做到这一点,但我还没有弄清楚。

新脚本放在这里:

for file in $(echo $1)
do

【问题讨论】:

  • 可以消除对外部cut的调用:IMGNAME=${file##*.}

标签: bash filter resize hidden glob


【解决方案1】:

我建议将脚本的命令行从 resize * 400x400 更改为 resize 400x400 *,这样脚本会更像标准的 unix 工具(grepsedln 等)。您不必在脚本中取消设置 dotglob 选项(这会更好,因为脚本的用户是否希望隐藏文件被全局化,这取决于脚本用户)。

您的脚本将如下所示:

#!/bin/bash

OUTPUTFORMAT=$1
# Remove original $1 from the list of arguments
shift

for i in "$@"
do
    # Use $OUTPUTFORMAT here
    etc....

如果您不想更改脚本的命令行。你可以尝试设置GLOBIGNORE

export GLOBIGNORE=".*"

或者,如果设置了extglob,您可以尝试像这样进行文件通配:

echo !(.*)

【讨论】:

  • 我希望语法与 convert 命令保持一致,它接受如下命令:convert [input file] [options] [output file],但我现在会接受你的建议。跨度>
  • 另外,如果我这样做,我不确定如何制作它以便可以省略输出格式。
  • 我假设 400x400 是输出格式。我已经编辑了我的脚本,以更清楚地说明如何跳过它。
  • 感谢您的帮助彼得。 400x400 是输出尺寸。输出格式是第二个参数。请参阅用法示例:resize * 400x400 jpg。用户可以选择是指定输出格式还是保留输入文件的格式。因此,我需要根据是否指定输出格式来转换一次或两次。
  • 嗯,由于您的输出格式是可选的,因此似乎无法使用位置参数来解决此问题。标志应该可以工作。执行此操作的标准方法是使用 getopts。见 man getopts。
【解决方案2】:

有一个dotglob shell 选项可以决定在通配时是否包含以. 开头的文件。您可以检查是否是这种情况

shopt dotglob

您也可以在脚本中明确禁用它:

#!/bin/bash

shopt -u dotglob

for file in $1/*; do
  ...
done

【讨论】:

  • 由于某种原因尝试在脚本中设置 dotglob 参数不起作用。如果我在 shell 中运行 shopt -u dotglob,则 echo * 具有所需的参数,但如果我将该行放入脚本中并执行它,它不会更改参数。
【解决方案3】:

没有必要将 ls 与 for 循环一起使用,大多数时候它是无用的。除非您特别指定,否则带有 * 的 for 循环也不会返回隐藏文件。要显示隐藏文件,

for files in .*
do
 echo $files
done

【讨论】:

  • 请记住,我希望使用位置参数 $1 作为参数,以便可以使用任何 globber。
  • 此外,将 shopt dotglob 设置为“yes”,* 将返回隐藏文件。不幸的是,我似乎无法使用脚本更改此参数。
【解决方案4】:

当您获得 $* 中的文件列表时,您可以逐个检查它们

for i in $*
do 
   expr $i : '^\..*' > /dev/null && continue
   # process file
done

【讨论】:

  • 请记住,我不希望脚本自动作用于当前目录中的所有文件。我希望能够使用所有的globbers,所以测试必须是“echo $1 | [filter]”的形式,除非echo可以做过滤器或者我根本不需要echo。它需要使用位置参数。
  • $* 返回所有位置参数,包括我的图像尺寸和输出格式参数。
  • 如果您将调用语法更改为“resize 400x400 ”,您可以将参数移出 $。 (这也类似于其他实用程序处理参数的方式,即 grep [SWITCHES] file1 file2 ...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-05-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-15
  • 2013-12-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多