简体   繁体   English

在 macOS 上使用 Bash 递归重命名文件和目录

[英]Recursively Rename Files and Directories with Bash on macOS

I'm writing a script that will perform some actions, and one of those actions is to find all occurrences of a string in both file names and directory names, and replace it with another string.我正在编写一个将执行一些操作的脚本,其中一个操作是在文件名和目录名中查找所有出现的字符串,并将其替换为另一个字符串。

I have this so far到目前为止我有这个

find . -name "*foo*" -type f -depth | while read file; do
    newpath=${file//foo/bar}
    mv "$file" "$newpath"
done

This works fine as long as the path to the file doesn't also contain foo , but that isn't guaranteed.只要文件的路径也不包含foo ,这就可以正常工作,但这不能保证。

I feel like the way to approach this is to ONLY change the file names first, then go back through and change the directory names, but even then, if you have a structure that has more than one directory with foo in it, it will not work properly.我觉得解决这个问题的方法是只更改文件名,然后 go 回来并更改目录名,但即便如此,如果你的结构中有多个包含foo的目录,它不会好好工作。

Is there a way to do this with built in macOS tools?有没有办法使用内置的 macOS 工具来做到这一点? (I say built-in, because this script is going to be distributed to some other folks in our organization and it can't rely on any packages to be installed). (我说是内置的,因为这个脚本将分发给我们组织中的其他一些人,它不能依赖任何要安装的包)。

Separating the path_name from the file_name, something like.将 path_name 与 file_name 分开,类似于。

#!/usr/bin/env bash

while read -r file; do
  path_name="${file%/*}"; printf 'Path is %s\n' "$path_name"
  file_name="${file#"$path_name"}"; printf 'Filename is %s\n' "$file_name"
  newpath="$path_name${file_name//foo/bar}"
  echo mv -v "$file" "$newpath"
done < <(find . -name "*foo*" -type f)

Have a look at basename and dirname as well.看看basenamedirname以及。

The printf 's is just there to show which is the path and the filename. printf只是用来显示路径和文件名。

The script just replace foo to bar from the file_name, It can be done with the path_name as well, just use the same syntax.该脚本只是将文件名中的foo替换为bar ,也可以使用路径名来完成,只需使用相同的语法即可。

newpath="${path_name//bar/more}${file_name//foo/bar}"

So renaming both path_name and file_name.所以重命名 path_name 和 file_name。

Or renaming the path_name and then the file_name like your idea is an option also.或者重命名 path_name 然后像您的想法一样重命名 file_name 也是一个选项。

path_name="${file%/*}"
file_name="${file#"$path_name"}"
new_pathname="${path_name//bar/more}"

mv -v "$path_name" "$new_pathname"

new_filename="${file_name//foo/bar}"

mv -v "${new_pathname%/*}$file_name" "$new_pathname$new_filename"

There are no additional external tool/utility used, except from the ones being used by your script.除了脚本使用的工具/实用程序之外,没有使用其他外部工具/实用程序。

Remove the echo If you're satisfied with the result/output.如果您对结果/输出感到满意,请删除echo

You can use -execdir to run a command on just the filename (basename) in the relevant directory:您可以使用-execdir相关目录中的文件名(基名)运行命令:

find . -depth -name '*foo*' -execdir bash -c 'mv -- "${1}" "${1//foo/bar}"' _ {} \;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM