递归创建符号链接,如果文件 1.JPG 存在,则将其重命名为 1A.JPG

递归创建符号链接,如果文件 1.JPG 存在,则将其重命名为 1A.JPG

我有一个 shell 脚本,用于创建一年中所有照片的符号链接。这些照片来自不同的相机,位于子目录中。

f=$(pwd);
export f;
q="2015/";
z="2015_Links/";
find $q/. \( -name "*.CR2" -o -name "*.JPG" \) -execdir sh -c 'ln -s "$PWD"/$(basename {}) "$f"/"$z"/Link_$(basename {})' {} \;

某些照片具有相同的文件名,导致错误:

ln: failed to create symbolic link ‘2015_Links/Link_IMG_1588.CR2’: File exists

在这种情况下,我想重命名这些现有文件。例如,Link_IMG_1588.CR2Link_IMG_1588A.CR2.

答案1

我找到了该问题的另一种解决方案。

我成功地从不同的相机重命名了我的照片(使用findexiv2),以便每个文件名都是唯一的(IMG 编号 + 日期):

find 2015/. \( -name "*.CR2" -o -name "*.JPG" \) -execdir sh -c 'exiv2 -r':basename:_%Y%m%d_%H_%M_%S' rename $(basename {})' {} \;

答案2

战略:

  • 测试理想的目标文件名是否存在。
  • 如果是,请尝试添加数字后缀-1-2等。

其他改进:

  • 使用-exec … {} +而不是-execdir … {} \;稍微提高性能。您实际上不需要-execdir这里,因为您正在建立绝对链接。
  • 使用$x(或者$1如果您坚持使用… {} \;)而不是{}在内壳中。切勿{}在 shell 代码段内使用find -exec: ,它将文件名直接插入到 shell 脚本中,因此它会被解析为 shell 语法,如果文件名包含任何在 shell 语法中具有特殊含义的字符,则会崩溃。始终{}作为单独的参数传递。

代码(未经测试):

find "$q/." \( -name "*.CR2" -o -name "*.JPG" \) -exec sh -c '
    for x; do
      base=$0/Link_${x##*/}; base=${base%.*}; ext=${x##*.}
      if [ -e "$target.$ext" ]; then
        suffix=1;
        while [ -e "${base}-$suffix.$ext"; do suffix=$((suffix+1)); done
      fi
      ln -s -- "$PWD/${x##*/}" "$target"
    done
  ' "$PWD/$z" {} +

相关内容