使用单个 bash 命令批量重命名文件夹

使用单个 bash 命令批量重命名文件夹

我有这样的文件夹设置:

/path/to/directory/SLUG_1/SLUG_1 - SLUG_2 - SLUG_3

SLUG_2 是年份,年份后面可能有字母,如“1994”或“2003a”。

我想将这些文件重命名为:

/path/to/directory/SLUG_1/SLUG_2 - SLUG_3

我已经非常接近这个命令了:

find $root -mindepth 2 -maxdeth 2 -type d | sed "s#\(\(/path/to/directory/[^/]*/\).* - \([0-9]\{4\}[a-bA-B]\? - .*\)\)#mv "\1" "\2\3"#

这打印:

mv "/path/to/directory/SLUG_1/SLUG_1 - SLUG_2 - SLUG_3" "/path/to/directory/SLUG_1/SLUG_2 - SLUG_3"

这正是我想要执行的命令。但我无法执行它。

我尝试将输出分配给变量并通过调用该变量来执行它。那行不通。我尝试了这个想法的一些变体,但出现了错误。

感觉就像我在这里缺少一些工具。一些迭代工具可以使这项工作变得容易。有什么建议么?

答案1

假设所有子目录都/path/to/directory遵循该命名约定:

cd /path/to/directory
prename -n 's~/\d{4}[a-z]? - ~/~i' */*

prename是个Perl重命名(任何变体都可以)。

答案2

这打印:

mv ...

这正是我想要执行的命令。但我无法执行它。

我尝试将输出分配给变量并通过调用该变量来执行它。那行不通。我尝试了这个想法的一些变体,但出现了错误。

感觉就像我在这里缺少一些工具。

您正在寻找的简单方法是附加| bash到您的命令中。这就是如何从“打印命令的命令”到“实际运行打印的命令”。

但是,即使您在要打印的命令中包含双引号,这是一个馊主意包含在脚本中。

您可能已经处理了空格方面的问题,但是如果文件名直接包含双引号字符怎么办?还是换行符?或者变量名(将在双引号内展开)?

仅有的文件名中非法的字符是斜杠 ( /) 和空字节。

在编写脚本时,您应该保持比交互式命令行更高的稳健性标准。

在命令行中,您可以看到要运行的命令,可以确认它是否正确,然后可以运行它。在剧本中,没有监督,也没有确认。该脚本将执行您告诉它执行的操作,无论这可能会产生多大的破坏性。

所以正确的方法实际上是使用find,详见我的其他答案。这将处理任何文件名正确并且不包含任意代码执行漏洞。

答案3

另一个答案是使用 GNUfind来处理重命名。无论文件名中包含哪些字符,此方法都很可靠。

如果我正确理解您的用例,您想要重命名以其父目录的全名开头的目录。换句话说,如果您的目录是这样命名的:

/some/path/abcdefghi/abcdefghi - something - else/

你想像这样重命名它:

/some/path/abcdefghi/something - else/

由于您在这个问题上指定了 GNU 作为标签,因此您可以使用该find命令的 GNU 扩展并按如下方式处理:

find . -mindepth 2 -maxdepth 2 -type d -regextype posix-egrep -regex '.*/([^/]+)/\1[^/]+' -exec sh -c 'new="$(sed -r "s:/([^/]+)/\\1 ?-? ?([^/]+)\$:/\\1/\\2:" <<<$1)"; mv "$1" "$new"' find-sh {} \;

检测结果:

[vagrant@localhost test]$ mkdir -p SLUG_1/SLUG_{1\ -\ SLUG_{2..4}\ -\ SLUG_5,7\ -\ something}
[vagrant@localhost test]$ find . -type d
.
./SLUG_1
./SLUG_1/SLUG_1 - SLUG_2 - SLUG_5
./SLUG_1/SLUG_1 - SLUG_4 - SLUG_5
./SLUG_1/SLUG_1 - SLUG_3 - SLUG_5
./SLUG_1/SLUG_7 - something
[vagrant@localhost test]$ find . -mindepth 2 -maxdepth 2 -type d -regextype posix-egrep -regex '.*/([^/]+)/\1[^/]+' -exec sh -c 'new="$(sed -r "s:/([^/]+)/\\1 ?-? ?([^/]+)\$:/\\1/\\2:" <<<$1)"; mv "$1" "$new"' find-sh {} \;
[vagrant@localhost test]$ find . -type d
.
./SLUG_1
./SLUG_1/SLUG_3 - SLUG_5
./SLUG_1/SLUG_4 - SLUG_5
./SLUG_1/SLUG_2 - SLUG_5
./SLUG_1/SLUG_7 - something
[vagrant@localhost test]$ 

相关内容