我在一个目录中有很多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 -
答案 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
或者更有用的是搞乱文件名:
因此,您使用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)
在处理循环时,带有空格的文件名会导致问题。 您可以通过以下几种方式处理此问题:
使用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变量更改为仅包含换行符或类似内容。要了解有关详情,请参阅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