繁体   English   中英

使用grep和regex打印文件

[英]printing files with grep and regex

我的目录中有很多mp3文件,文件名和数字和空格的组合不同。 当我运行ls | grep ^[0-9][0-9]" -" ls | grep ^[0-9][0-9]" -"我得到的输出如下

01 - Hotel California.mp3
02 - Heartache Tonight.mp3
03 - The Long Run.mp3
04 - One Of These Nights.mp3

但是当我for i in ``ls | grep ^[0-9][0-9]" -"``;do echo $i; done for i in ``ls | grep ^[0-9][0-9]" -"``;do echo $i; done for i in ``ls | grep ^[0-9][0-9]" -"``;do echo $i; done我得到的结果相同,但以不同的格式

01
-
Hotel
California.mp3
02
-
Heartache
Tonight.mp3

为什么会这样呢? 我该如何即兴创作呢? 我想做的是将01 -替换为Eagles -

有关您在做什么的错误,请参见http://mywiki.wooledge.org/BashFAQ/001 您必须小心使用带有空格的命令输出,以确保不要在将其拆分为单词的上下文中使用它。

在您的特定示例中,您实际上不需要正则表达式。 Shell glob表达式可以解决问题。

for i in [0-9][0-9]' -'*; do
    mv "$i" "${i// /_}";  # / at start of pattern = all matches.
done

或更有用的是摆弄文件名:

  • (基于Perl的重命名器,在perl软件包中打包在Debian / Ubuntu中)
  • mmv 'foo*.mp3' 'bar#1.mp3' mmv 'foo*.mp3' 'bar#1.mp3'

因此,用Eagles替换曲目号的目标是:

prename 's/[0-9]+ -/Eagles -/' *.mp3

或钉Eagles -每个文件名的开头。

prename 's/^/Eagles - /'  [0-9]*.mp3  # or:
prename '$_ = "Eagles - " . $_'  [0-9]*.mp3  # you aren't limited to the s// operator, it really does eval as perl code.

请注意,如何使用Shell Glob来选择要在prename上运行prename文件,因此您的实际模式不必避免匹配文件名,您可以使用其他方法进行过滤。 如果要在模式中使用/ (例如,将文件移动到子目录),建议使用s{pat}{repl}语法。 这比sed转换为\\/的森林好得多。

有一个shopt -s extglob bash选项 ,但是最好使用正则表达式来代替它,除非您正在编写shell脚本以达到最大效率。 (例如,每次有人按下tab时运行的可编程完成功能)。

在文件名中带有空格的文件在处理循环时会引起问题。 您可以通过以下几种方法来处理:

  1. while read使用:

    ls | grep -E "^[0-9][0-9] -"| while read line do mv "$line" new_name done

  2. 使用find -print0和perl:以下命令将提供您要查找的输出:

    find ./ -print0 | perl -0 -n -e 'print "$_\\n" if /[0-9][0-9] -/;'

    您还需要更改文件名的帮助吗?

  3. 将IFS变量更改为仅包含换行符或类似内容。 要了解更多信息,可以阅读这篇文章

这是在另一个答案中提到的,但此处的周围文本要少得多:

$ rename 's/^\d\d - /Eagles - /' *.mp3

当比您有经验的人比您做得干净得多时,不要重塑方向盘。

编辑:尝试awk唯一方法:

ls <music dir> | awk '/^[0-9][0-9] - .+\.mp3/{$1="Eagles"; print $0}'

Bash中的for将一个循环中的每个单词解释为一个“对象”。 为了避免这种情况,您必须将命令放在引号中

➜  songs  touch "01 - foo"
➜  songs  touch "02 - bar"
➜  songs  touch "03 - baz"
➜  songs  for SONG in "$(ls | grep -E "^[0-9][0-9] -")"; do echo $SONG; done;
01 - foo
02 - bar
03 - baz

然而:

➜  songs  for SONG in $(ls | grep -E "^[0-9][0-9] -"); do echo $SONG; done;
01

foo
02

bar
03

baz

编辑:适用于zsh,但不适用于bash。 这是bash版本:

~/tmp/songs$ for SONG in $(ls | grep -E "^[0-9][0-9] -"); do echo $SONG; done;
01
-
foo
02
-
bar
03
-
baz
~/tmp/songs$ IFS=$(echo -en "\n\b")
~/tmp/songs$ for SONG in $(ls | grep -E "^[0-9][0-9] -"); do echo $SONG; done;
01 - foo
02 - bar
03 - baz

也许我错了,但是您可能正在计划对它们进行重命名或其他操作。

如果在“ ls |”之后使用| xargs 可以为您提供正确的参数。 但是,即使在这里,我还是建议您使用“ ls -1”选项(是的,那里是数字1,每个目录/文件都列在1列中。从命令的角度来看,找出1个文件名从何处开始以及其他结尾何处更好) )

要一次将整行读入一个循环,您可以使用已经提到的选项:慢移IFS变量,然后在完成后将其改回。 或者还有另一种优雅的方式来处理空间:

ls -1 *.mp3|while read line;do echo $line ;done

最后,我使用以下命令完成了此操作。 感谢您的所有投入

for i in [0-9][0-9]' -'*; do 
    mv $i `ls $i | grep ^[0-9][0-9]" -" | \
    sed 's/^[0-9][0-9] - /Eagles - /g'`
done

暂无
暂无

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

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