如何使用find命令从文件名中删除(1)


13

我最近在Mac OS 10.7(Lion)上使用XLD将所有FLAC文件转换为44.1 kHz的较低采样率和24位的位深(因为iPhone / iPod不支持高于此的任何东西)。

尽管我告诉XLD改写了以前的所有文件,但XLD (1)在文件末尾附加了一个

some_song.m4a

some_song(1).m4a

所以现在我(1)要从我转换的所有FLAC文件中删除该文件。

我知道我可能已经使用某些程序甚至AppleScript重命名了文件,但是我想学习使用老式的命令行方法。

我知道这find . -name *\(1\).m4a将获取所有已转换的FLAC文件。

接下来,我知道我必须做的东西-execmv重命名所有找到的文件。但是我不知道是如何保留原始文件名而仅删除(1)

也许我需要进行一些组正则表达式捕获来存储我不想修改的文件名的一部分?或者也许不可能一齐完成所有操作,而我应该创建一个shell脚本(我做起来不太舒服,但是我愿意尝试一下)。

欢迎任何提示或建议!谢谢!


5
为什么要下票?似乎是一个有效的问题……

与您的特定问题无关(在上find),但可能正在解决您的实际问题(转换音频文件),您可能有兴趣查看audiotools.sourceforge.net和本示例案例(对于macosx lion)invibe.net/ LaurentPerrinet / SciBlog / 2012-04-22
meduz,2012年

Answers:


13

find除非万不得已,否则不要尝试解析输出。重要的是要意识到,在Unix文件系统上,文件名不是字符串(常见的误解),而是二进制的Blob,它可以包含除/Null字符之外的任何字符。安全正确地解析文件名已经足够让您避免在99%的时间中完全避免文件名的痛苦(只需查看@yarek答案中sed表达式有多毛,甚至不能涵盖所有情况)。 。幸运的是,在这种情况下,有一个更简单的方法:

find . -name '*(1).m4a' -execdir sh -c \
'for arg; do mv "$arg" "${arg%(1).m4a}".m4a; done' _ {} \+

整洁的方法,但仍像sed表达式一样毛茸茸:) +1
yrk

1
这里缺少什么...在哪里done
约克(yrk)

@yarek谢谢你的收获。此方法与sed管道方法之间的最大区别在于,此方法更加安全。只要您了解一些基本的shell脚本构造,它仍比正则表达式反斜杠汤更易于阅读。
jw013

你是对的; 这要干净得多。并且该$arg变量使其更易于阅读。
hobbes3 2012年

1
@DQdlM我上面发布的代码片段只是使用相当可移植的POSIX语法进行find调用sh。有关更多详细信息,您可以查看有关参数扩展部分,说明for循环的复合命令部分以及POSIX find规范。除了这些资源,我很乐意回答您的任何特定问题。
jw013

6

在Debian和Ubuntu上,我可以rename 's/\(1\)//' *.m4a用来解决您的问题。


奇怪,我可以做的man rename,但我居然没有rename-bash: rename: command not foundwhich rename不显示任何东西)。
hobbes3 2012年

在Mac上,@ hobbes3在这里man -a rename找到重命名(2)-系统调用,并重命名(n)-TCL 命令。既没有重命名(1),也没有实用程序本身。
约克(yrk)2012年

1
IIRC rename是Perl脚本,包含在一些perl安装中所包含的示例中,并且一些发行版将它包含在路径中,因为它是一个方便的命令。(@Hobbes也许您可以在互联网上找到它)
Kevin

我系统上的@Kevin rename是正常的二进制文件(不是perl)。但是,另一个警告是,并非所有版本的rename支持正则表达式。例如,我的版本仅允许您直接替换字符串,例如rename '(1)' '' *.m4a
Patrick

1
Perl rename脚本仅由Debian及其衍生版本安装。其他Linux系统具有不同的rename实用程序(Patrick显示)。OSX都没有。
吉尔(Gilles)'所以

4

在zsh中,使用zmv

autoload zmv      # you can put this line in your .zshrc
zmv '(*)\(1\)(*)' '$1$2'

在第二个参数(新名称)中,$1$2引用(PATTERN)源模式中带括号的组。编写此重命名的另一种方法是

zmv '(*)' '${1/\(1\)/}'

3

以下方法使您能够执行命令之前预览/修剪所生成的命令,并且这种方法非常可移植:它不仅应在Mac上运行,不仅应与bash配合使用,而且不仅应与GNU sed配合使用;即使在没有find(1)命令的系统上,也可以du毫无问题地用(1)替换它。

find . -name '*(1).m4a' |
sed 's/\(.*\)(1).m4a$/mv & \1.m4a/' 

如果对打印的命令满意,请重新运行并| sh -x附加。

如果担心文件名中的空格,请添加另一个s以转义所有空格:

find . -name '*(1).m4a' |
sed -e 's/ /\\ /g' -e 's/\(.*\)(1).m4a$/mv & \1.m4a/'

如果还需要其他特殊字符,它会变得有些棘手:

find . -name '*(1).m4a' |
sed -e "s/'/'\\\\''/g" -e 's/\(.*\)(1).m4a$/mv '\''&'\'' '\''\1.m4a'\'/

第一个函数将所有内容转换'为某种形式,以使它们在'...'-escaped字符串中间时按字面意义使用。第二个函数生成mv命令,其参数包含在中'...'


1
该命令不会转义文件名(空格,(和其他所有特殊字符)或在文件名周围添加引号。我尝试修改您的命令,但无法弄清楚如何在mv命令的两个文件名之间添加引号。命令的结果输出之一是mv ./The Beatles - Let It Be (MFSL LP 1-109) 24-96 Vinyl Rip/01 Two Of Us(1).m4a ./The Beatles - Let It Be (MFSL LP 1-109) 24-96 Vinyl Rip/01 Two Of Us.m4a。如果我运行该命令,我会得到-bash: syntax error near unexpected token '('
hobbes3 2012年

这应该是家庭作业:)但是好吧,我将更新答案
yrk

顺便说一下,GNU sed可以通过e在替换后添加命令来执行命令本身。例如,find . -name '*(1).m4a' | sed 's/\(.*\)(1).m4a$/mv & \1.m4a/e'将执行命令而无需将管道连接到sh -x

@Rush是执行此操作的唯一sed;并且无论如何它都需要启动shell,但是每个命令都要有一个新命令(提醒make的问题,不是吗?)
yrk 2012年

2
我认为我们不应该投票。毕竟,这是一个有效的解决方案。
hobbes3 2012年

1

这是一个执行此操作的小脚本:

for var in `find . -type f -name "*(1).m4a"`; do
    new=`echo $var | cut -d'(' -f1`;
    mv $var $new.m4a;
done

这会扼杀文件名中带有空格的文件;还需要足够大的临时存储空间,以便`find ...`
yrk 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.