【问题标题】:bash: rename files in indeterminate sub-subfolders based on grandparent directory namebash:根据祖父目录名称重命名不确定子文件夹中的文件
【发布时间】:2023-11-30 00:18:02
【问题描述】:

Bash 新手在这里尝试将文件夹的名称插入到该文件夹​​内的某些文件中。

问题是这些文件在主目录的子文件夹的子文件夹中,而且每个级别的名字都不一样。

例如,主文件夹interviews 可能包含John Doe,而在John Doe 下是一个目录Images,其中包含一个文件Screenshot.jpg。但也可能有John Smith 的文件夹Etc,其中12_Screenshot 2.jpg

我想重命名所有这些包含Screenshot 的文件,在文件名前插入John DoeJohn Smith

我尝试调整我找到的几个脚本并从interviews 目录运行它们:

for i in `ls -l | egrep '^d'| awk '{print $10}'`; do  find . -type f -name "*Screenshot*" -exec sh -c 'mv "$0" "${i}${0}"' '{}' \; done

之后终端给出插入符号提示,就好像我遗漏了什么一样。我也试过了

find -regex '\./*' -type d -exec mv -- {}/*/*Screenshot* {}/{}.jpg \; -empty -delete

返回find: illegal option -- r

理论上第二个将文件向上移动到父文件夹这一事实不是问题,因为无论如何我最终都必须这样做。

【问题讨论】:

  • 所以你想要interviews/John Doe/images/Screenshot.jpg -> interviews/John Doe/images/John Doe-Screenshot.jpg?
  • 我认为您在第一次尝试中可能会在\; 之后丢失;。但无论如何你都不应该解析ls 的输出。
  • @MarcB 完全正确。 @EtanReisner 我试过for i in $( ls ); do find . -type f -name "*Screenshot*" -exec sh -c 'mv "$0" "${i}${0}"' '{}' \; ; done。它执行但没有效果。 i 在 mv 字符串中似乎为空。
  • 那是因为你把它放在单引号里=没有替换
  • @Ionewasp mv 命令,还是括号?

标签: macos bash directory batch-rename


【解决方案1】:

以下脚本将按需要运行:

dir=$1
find $dir -name "*Screenshot*" -type f | while read file
do
    base=$(basename $file)
    dirpath=$(dirname $file)
    extr=$(echo $file | awk -F/ '{print $(NF-2)}') #extracts the grandparent directory
    mv $file $dirpath/$extr-$base
done

正如@loneswap 提到的,这必须作为脚本调用。所以如果你的主目录是mainDir,那么你会这样调用它...

./script mainDir

【讨论】:

  • 返回错误:find: illegal option -- n。这没有意义,因为它看起来不错。
  • @fvogel 您需要将其作为脚本调用,将目录的一个参数传递给进程
  • @lonewasp 我应该仔细看看。像魅力一样工作!
  • @Bolboa 不错的解决方案!您能否建议如何将重命名的文件移动到新位置,同时保持原始文件不变
  • 我想通了(重命名并复制到新位置):在第 2 行添加 dst = $1,在最后一行添加 cp $dirpath/$extr-$base $dst
【解决方案2】:

对于当前工作目录中的每个目录,递归查找包含字符串“screenshot”的文件(OSX 不区分大小写)。将找到的路径拆分为父部分(始终至少以'./'形式存在)和文件名,产生两行原始文件路径,第二行原始文件夹+修改后的目标文件名。使用两个参数通过 xargs 执行 mv 命令(由换行符分隔以允许路径中的空格):

for i in `ls -l | sed -n '/^d\([^[:space:]]\+[[:space:]]\+\)\+\([^[:space:]]\+\)$/s//\2/p'`; do
    find "$i" -type f -iname "*Screenshot*" \
        | sed -n '\!^\(\([^/]\+/\)\+\)\([^/]\+\)$!s!!\1\3\n\1'$i'\3!p' \
        | xargs -d '\n' -n 2 mv;
done

缺点:OSX 上的 xargs 不知道 --no-run-if-empty,因此对于不包含带有“screenshot”字符串的文件的目录,将调用空 mv。需要添加正确的选项(无权访问 OSX 手册页)或 xargs ... 2>&/dev/null 以忽略所有错误...

【讨论】:

  • 尝试在 egrep 之后用你的 awk 调用替换我的 sed,在我的情况下(Ubuntu/bash) ls -l 提供的组件少于 10 个,而我的意图是得到最后一个。
  • 还可以尝试在 mv 之前添加 echo 以查看将调用哪些命令
  • awk '{print $10}'` 替换sed '...'` ; 我得到:~/Desktop/interviews/interview_name ~/Desktop/interviews ~/Desktop/test usage: mv [-f | -i | -n] [-v] source target mv [-f | -i | -n] [-v] source ... directory ~/Desktop/interviews ~/Desktop/test
  • 使用 echo 我在输出中间得到了 mv ./images/The_Screenshot_12.jpg 行。
  • 路径中有空格吗?