[英]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
或更有用的是摆弄文件名:
因此,用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
时运行的可编程完成功能)。
在文件名中带有空格的文件在处理循环时会引起问题。 您可以通过以下几种方法来处理:
while read
使用:
ls | grep -E "^[0-9][0-9] -"| while read line do mv "$line" new_name done
使用find -print0和perl:以下命令将提供您要查找的输出:
find ./ -print0 | perl -0 -n -e 'print "$_\\n" if /[0-9][0-9] -/;'
您还需要更改文件名的帮助吗?
将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.