Bash 在shell的一行中重命名多个文件 问题
目录中有以下格式的文件:*-foo-bar.txt 示例目录:Bash 在shell的一行中重命名多个文件 问题,bash,shell,Bash,Shell,目录中有以下格式的文件:*-foo-bar.txt 示例目录: $ ls *-* asdf-foo-bar.txt ghjk-foo-bar.txt l-foo-bar.txt tyui-foo-bar.txt bnm-foo-bar.txt iop-foo-bar.txt qwer-foo-bar.txt zxcv-foo-bar.txt $ ls *.txt asdf.txt bnm.txt ghjk.txt iop.txt l.txt qwer.txt
$ ls *-*
asdf-foo-bar.txt ghjk-foo-bar.txt l-foo-bar.txt tyui-foo-bar.txt
bnm-foo-bar.txt iop-foo-bar.txt qwer-foo-bar.txt zxcv-foo-bar.txt
$ ls *.txt
asdf.txt bnm.txt ghjk.txt iop.txt l.txt qwer.txt tyui.txt zxcv.txt
所需目录:
$ ls *-*
asdf-foo-bar.txt ghjk-foo-bar.txt l-foo-bar.txt tyui-foo-bar.txt
bnm-foo-bar.txt iop-foo-bar.txt qwer-foo-bar.txt zxcv-foo-bar.txt
$ ls *.txt
asdf.txt bnm.txt ghjk.txt iop.txt l.txt qwer.txt tyui.txt zxcv.txt
解决方案1
我想到的第一个解决方案看起来有点像这个丑陋的黑客:
ls *-* | cut -d- -f1 | sed 's/.*/mv "\0-foo-bar.txt" "\0.txt"/' > rename.sh && sh rename.sh
上述解决方案会动态创建一个脚本来重命名文件。此解决方案还尝试解析ls
的输出,这不是一件好事情
解决方案2
使用以下shell脚本可以更优雅地解决此问题:
for i in *-*
do
mv "$i" "`echo $i | cut -f1 -d-`.txt"
done
上述解决方案使用循环重命名文件
问题:
有没有一种方法可以在一行中解决这个问题,这样我们就不必显式地编写循环脚本、生成脚本或调用新的或当前的shell(即避免sh、bash等命令)?您尝试过该命令吗
例如:
rename 's/-foo-bar//' *-foo-bar.txt
如果没有,我将使用find
、sed
和xargs
:
find . -maxdepth 1 -mindepth 1 -type f -name '*-foo-bar.txt' | sed 's/-foo-bar.txt//' | xargs -I{} mv {}-foo-bar.txt {}.txt
这并不能回答您的问题,但是--请注意,
$(echo$i | cut-f1-d-).txt
可以用${i%%-*}.txt
的形式编写。此外,如果您担心解析ls
不是一件好事,那么您还应该更好地使用双引号:mv“$i”“${i%%-*}.txt”
。为什么要避免循环?在这种情况下,循环可能更有效,因为所有事情(除了mv
)都可以由shell完成,而不是调用外部命令,如find
、sed
、cut
等。@ruakh感谢您的评论。在最初的文章中,我指定文件名中没有空格。因此,我草率地使用了双引号。然而,现在我更新了我的帖子,以消除这一限制,支持更普遍的解决方案。谢谢你的${i%%-*}.txt
提示。@Susanpal:我确实注意到你说没有空格;但是,双引号也会阻止解释shell元字符,如*
和?
和[
(如果$foo
设置为*
,则echo“$foo”
将打印星号,而echo$foo
将打印当前目录中的文件列表。)外部命令管道比本机shell循环更昂贵。但无论您使用什么,您都必须重复调用mv
,因为mv
一次只能重命名一个文件。这基本上是Tim在下面的回答中所做的。xargs
可以作为perl的脚本可作为用户运行。或者只对*-foo-bar.txt中的文件执行;回显“mv'$file'${file%-foo-bar.txt}.txt'”;完成| sh
,但如果文件名中有单引号,则会中断。