在多个文件夹中重命名多个文件名

时间:2016-02-19 01:28:52

标签: bash shell

我知道您可以使用以下内容重命名单个文件夹中的所有文件名:

$parsed = preg_split('/\s+/',$string); 
$page_is = array_shift($parsed_url); 
$getVars = array(); 
foreach($parsed as $argument) { 
    list($variable,$value) = explode("=",$argument); $getVars[$variable] = $value; 
}

但是,有没有办法在多个文件夹中执行此操作?例如,它将搜索当前目录中的所有文件夹并进行更改。

我有for file in 1_*; do mv "$file" "${file/1_/}" done 版本4.3

2 个答案:

答案 0 :(得分:1)

一个强大的解决方案,假设你有 GNU BSD / OSX find

find . -type f -name '1_*' -execdir sh -c 'echo mv -- "$1" "${1#1_}"' _ {} \;

注意:
- 为了安全,这只会回显 mv命令;删除echo以执行实际重命名 - OP的替换,"${file/1_/}"已更改为符合POSIX的"${file#1_}",实际上更接近意图。
- 如果您确实需要"${file/1_/}"替换,系统上的sh可能支持或不支持,则最好显式调用已知支持它的shell ,例如bash - 符号链接被忽略(文件和目录);使用find -L ...包含它们(作为要重命名的潜在文件,并使find下降到符号链接到目录)。 功能

  • find . -type f -name '1_*'在当前目录(-type f)子树中查找名称与1_*-name '1_*')匹配的所有文件(.)。< / LI>
  • -execdir执行传递给它的命令在当前文件所在的子目录中
  • sh -c 'echo mv -- "$1" "${1#1_}"' _ {} \;调用默认shell(sh):
    • 带有命令字符串(传递给-c
      • mv -- "$1" "${1#1_}"有效地从第一个位置参数(1_)表示的文件名中删除前缀$1
    • 和虚拟参数_sh将分配给$0,此处不感兴趣)
    • 和手头文件的路径{},shell将绑定到$1;
    • \;只会终止-execdir的论点。

请注意,--可确保恰好以-开头的任何文件名都不会被mv误认为是选项(在下面类似地适用)。

-execdir不符合POSIX标准;如果符合POSIX的变体因此更麻烦:

find . -type f -name '1_*' -exec sh -c \
  'cd -- "${1%/*}" && f=${1##*/} && echo mv -- "$f" "${f#1_}"' _ {} \;
  • cd -- "${1%/*}"更改手头文件所在的目录。
    • 注意:cd -- "$(dirname -- "$1")"通常更强大,但效率更低;由于我们知道$1始终是路径而不是此方案中的纯文件名,因此我们可以使用效率更高的cd -- "${1%/*}"
  • f=${1##*/}从文件路径中提取纯文件名。
  • 然后命令行的其余部分按上述方式工作,类似地。

效果记录

上述解决方案简洁,但效率低下,因为必须为每个匹配的文件生成一个shell实例。

潜在加速是使用peak's approach的变体,但只有在while循环中避免调用外部实用程序时才使用mv除外):

find . -type f -name '1_*' | while IFS= read -r f; do
   new_name=${f##*/}       # extract filename
   new_name=${new_name#1_} # perform substitution
   d=${f%/*}               # extract dir
   echo mv -- "$f" "$d/$new_name"  # call mv to rename
done

以上承担了使用嵌入换行符打破文件名的假设风险(非常罕见);使用GNU或BSD find,可以解决这个问题。

使用这种方法,只会生成单个 shell实例,它会在循环中处理所有匹配的文件名 - 只要在外部实用程序在循环为mv,这通常会比仅find的{​​{1}}解决方案更快。

答案 1 :(得分:1)

如果你不想依赖太多细微之处,可以考虑一下这种非常行人的做法,假设有一个类似bash的shell,并且所有常见的嫌疑人(发现,sed,......)都可以直接使用:< / p>

find . -type f -name "1_*" | while read -r file ; do
   x=$(basename "$file")
   y=$(sed 's/1_//' <<< "$x")
   d=$(dirname "$file")
   mv "$file" "$d/$y"
done

(您可能希望使用“mv -i”或“echo mv ....”尝试此操作。您可能还希望将find-follow选项一起使用。)