代码在终端中有效,但在重命名脚本中无效(使用空格操作文件名)

代码在终端中有效,但在重命名脚本中无效(使用空格操作文件名)

我想了解更多,所以我尝试编写脚本,而不仅仅是使用终端。我知道rename我可以使用重命名图像文件,rename 's/ /_/g' *.jpg但是当我在 shell 脚本中编写它以指向目录时:

DIRECTORY="/foo/bar"

for imgfile in $(find $DIRECTORY -type f -name \*.jpg); do
    echo 'replacing whitespace in' $(basename $imgfile)
    rename -f 's/ /_/g' *.jpg 
done

它不起作用,终端将获取一个文件(例如:)1234 abcd.jpg并回显abcd.jpg。那么我哪里错了?

答案1

文件名中的空格是有害的。

我发现该脚本存在三个问题:

  1. 当执行for...循环时,如果找到带有空格的文件,则会得到两个不同的值。即,如果您有文件"file1 1.jpg"并且"file2 2.jpg"您执行以下操作:

    for i in $(find . -type f -name \*.jpg); do 
       echo $i
    done
    

    你将拥有

    ./file1 
    1.jpg
    ./file2
    2.jpg
    

    因为 shell 会在空格处中断参数。该$(find ...)命令的输出将是

    ./file1 1.jpg 
    ./file2 2.jpg 
    

    这是为命令for指定的四个字$i--- 默认情况下,shell 在扩展时以相同的方式处理空格和换行符。

    你可以规避这个问题改变 IFS 字符

    你的第一行可能看起来像这样:

    IFS=$'\n' find $DIRECTORY -type f -name \*.jpg | while read -r imgfile; do
    
  2. 你正在为 for 循环提供单个文件名,因此你应该说:

    rename -f 's/ /_/g' "$imgfile"
    

    否则*.jpg将在当前目录中扩展,而不是在$DIRECTORY(请注意引号 --- 因为$imgfile其中会有空格)。

  3. 即使如此,如果$DIRECTORY某个路径部分中有空格,重命名也会失败(中间目录不存在)。

  4. 建议(保持简单):

    DIRECTORY="/foo/bar"
    cd $DIRECTORY
    rename -f 's/ /_/g' *.jpg
    

    没有达到你想要的效果?

添加:我的脚本(很久以前创建,当时 Unix 中还没有rename),是这样的 --- 它将删除当前目录中名称中包含空格和制表符的所有文件:

# 
ls -1  | grep -E " |\t" | while read i; do
    a=`echo $i | tr " \t" "__"`
    mv -v "$i" $a
done

已添加++此链接我发现研究这个答案非常好。

答案2

解析结果的最佳方法find是使用 null 终止输出-print0

#!/bin/bash

while IFS= read -d '' -r; do
    rename -f "s/ /_/g" "$REPLY"
    if [[ ! -f $REPLY ]]; then
        echo "Renaming file: $(basename "$REPLY")"
    fi
done < <(find -type f -name '*.jpg' -print0)

(无需循环即可进行管理)。

$ find -type f -name '*.jpg' \
    -exec bash -c 'rename -f "s/ /_/g" "$1"; \
    [[ -f $1 ]] || echo "Renaming file: $(basename "$1")"' _ '{}' \;

相关内容