用grep和regex打印文件

时间:2015-08-01 19:05:52

标签: regex linux bash shell grep

我在一个目录中有很多mp3文件,其中包含不同的数字和空格组合作为文件名。当我运行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循环做同样的事情时 for i in ``ls | grep ^[0-9][0-9]" -"``;do echo $i; done我得到的输出相同,但格式不同

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

为什么会这样?我该怎么做即兴表演呢?我要做的是用01 -

替换Eagles -

7 个答案:

答案 0 :(得分:3)

请参阅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

或者更有用的是搞乱文件名:

  • prename(基于perl的重命名器,在perl包中的Debian / Ubuntu中打包)
  • 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 globs选择要运行prename的文件,因此您的实际模式不必避免匹配文件名,您可以过滤其他方式。如果您想在模式中使用/(例如,将文件移动到子目录),我建议使用s{pat}{repl}语法。比sed单线更好,变成\/的森林。

有一个shopt -s extglob bash option,但你最好只使用正则表达而不是那个,除非你编写shell脚本以获得最大效率。 (例如,每当有人按下tab时都会运行的可编程完成函数。)

答案 1 :(得分:2)

在处理循环时,带有空格的文件名会导致问题。 您可以通过以下几种方式处理此问题:

  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变量更改为仅包含换行符或类似内容。要了解有关详情,请参阅this article

答案 2 :(得分:1)

在另一个答案中提到了这一点,但这里的文字周围的文字要少得多:

$CONTAINER

当一个比你更有经验的人完成它时,不要重新发明轮子,比你更干净。

答案 3 :(得分:0)

编辑:尝试awk只接近:

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

答案 4 :(得分: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

答案 5 :(得分:0)

也许我错了,但你猜你打算用它们做一些重命名或其他事情。

如果你在&#34; ls |&#34;之后使用| xargs;这可能会帮助您使用正确的参数。 但即使在这里,我也建议选择&#34; ls -1&#34;选项(是的,那是一个数字1,每个目录/文件在1列中列出。更好地找出1文件名从哪里开始,而另一个从命令角度结束)

为了将整行一行读入一个循环,你有了已经提到的选项:处理IFS变量,然后一旦完成,你就改回来了。 或者还有另一种处理空间的优雅方式:

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

答案 6 :(得分:0)

最后我用下面的命令做了。感谢所有输入

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