如何使用Bash删除文件名中的最后一个字符?

时间:2019-05-28 12:04:58

标签: bash rename file-rename

我在一个文件夹中有几个.txt文件,它们的名称如下:

file1.txt
file2.txt
file2.txt_newfile.txt
file3.txt
file4.txt
file4.txt_newfile.txt
file5.txt_newfile.txt
...

我正在尝试从文件名中删除_newfile.txt。如果该文件存在,则应使用新文件覆盖该文件(例如file2.txt将被替换,而file5.txt将被重命名)。

预期输出:

file1.txt
file2.txt # this was file2.txt_newfile.txt
file3.txt
file4.txt # file4.txt_newfile.txt
file5.txt #file5.txt_newfile.txt
...

我尝试了以下代码:

for i in $(find . -name "*_newfile.txt" -print); do 
mv -f "$file" "${file%????????????}"
done

但是,出现以下错误:

mv: rename  to : No such file or directory

我在做错什么,如何重命名这些文件?

3 个答案:

答案 0 :(得分:4)

您正在使用find的输出填充变量 i ,但是在mv调用中引用了未声明的变量 file 。因此它扩展为mv -f '' '',这就是为什么您收到没有此类文件或目录错误的原因。

您最好这样做:

find -type f -name '*_newfile.txt' -exec sh -c '
for fname; do
  mv -- "$fname" "${fname%_newfile.txt}"
done' _ {} +

如果这些文件全部位于同一文件夹中,则您甚至都不需要find,只是一个for循环将执行以下操作:

for fname in *_newfile.txt; do
  mv -- "$fname" "${fname%_newfile.txt}"
done

答案 1 :(得分:1)

对于许多人来说,这也许是一个不寻常的解决方案,但是对我来说,这是一项典型的vi工作。 许多人可能不记得了,即使使用调试输出(sh -x),也可以通过外壳通过管道传递vi缓冲区的内容。

在这种或类似情况下,我不想浪费太多时间来思考很酷的正则表达式或shell欺骗,我该怎么做...务实的方式... vi支持您;-)

我们在这里:

1. enter directory with those files that you want to rename
2. start vi
3. !!ls *_newfile.txt
note: the !! command prompts you at the bottom to enter a command, the output of the ls command fills the vi buffer
4. dG
deletes all lines from your position 1 to the end of buffer, with a copy of it in the yank buffer
5. PP
paste 2 times the yank buffer
6. !G sort
!G prompts you at the bottom to pipe the buffer through sort
now you have all the lines double to save the work of typing filename again
7. with a combination of JkJk
you join the lines, so you have now the filename 2 times in a line like here:
file2.txt_newfile.txt file2.txt_newfile.txt
8. now add a mv command at the beginning of each line using an ex command
:%s/^/mv /
9. now remove the not needed trailing "_newfile.txt", again with an ex command
:%s/_newfile.txt$//
Now you have i.e. the following line(s) in the vi buffer:
mv file2.txt_newfile.txt file2.txt
10 back to line 1 to that you feed the whole buffer to the shell in the next step
1G
11. feed the shell commands to the shell and show some debug command
!G sh -x
12. check the results in the folder within vi, you will get the output of the ls command into the buffer
!!ls -l

最后退出vi。

乍一看似乎很像很多步骤,但是如果您知道vi,那么它的运行速度就非常令人眼花and乱,而且您还有一个额外的优势,就是可以将指令保存到文件中以用于文档编制或其他工作来创建脚本等。

答案 2 :(得分:-1)

您以“ i”开头,然后引用“ f”。 试试这个:

for f in $(find . -name "*_newfile.txt"); do mv -f "$f" "${f%_newfile.txt}"; done