使用“mv”在文件名中添加换行符

使用“mv”在文件名中添加换行符

这是一个严肃的问题。我测试了一些awk脚本,并且需要名称中带有换行符的文件。


是否可以使用 向文件名添加换行符mv

我现在可以这样做touch

touch "foo
bar"

通过触摸,我在每次复制和粘贴时添加了换行符。但我无法fooReturnbar在 shell 中编写。

如何重命名文件以在文件名中包含换行符?


2015/06/28编辑; 07:08 下午

要在 I 中添加换行符zsh,可以使用Alt+Return

答案1

这是一个坏主意(在文件名中包含奇怪的字符)但你可以这样做

 mv somefile.txt "foo
 bar"

(您也可以完成mv somefile.txt "$(printf "foo\nbar")"mv somefile.txt foo$'\n'bar等...详细信息特定于您的外壳。我正在使用zsh

阅读更多关于通配,例如全局(7)。详细信息可能是特定于 shell 的。但要明白这/bin/mv 是(由你的外壳)给出的,通过执行(2), 一个扩大参数数组:参数扩展和通配符是调用 shell 的责任。

您甚至可以编写一个小型 C 程序来执行相同的操作:

#include <stdio.h>
#include <stdlib.h>
int main() {
  if (rename ("somefile.txt", "foo\nbar")) {
     perror("rename somefile.txt");
     exit(EXIT_FAILURE);
  };
  return 0;
}

将上面的程序保存在 中foo.c,编译然后gcc -Wall foo.c -o foo 运行./foo

同样,您可以使用 Perl、Ruby、Python、Ocaml 等编写类似的脚本。

但这是个坏主意。避免文件名中出现换行符(它会让用户感到困惑,并且可能会破坏许多脚本)。

实际上,我什至建议在文件路径中仅使用非重音字母、数字和+-/._% 字符(作为/ 目录分隔符)。 “隐藏”文件(以 开头.)应谨慎使用。我认为在文件名中使用任何类型的空格都是错误的。使用下划线(例如foo/bar_bee1.txt)或减号(例如foo/bar-bee1.txt

答案2

如果您使用 bash,此命令应该可以工作。

mv a $'b\nc'

答案3

我知道您要求mv解决方案,但是,尽管有警告,这可以轻松完成rename(在 Perl 包中):

~/tmp$ touch foo
~/tmp$ rename 's/$/\nbar/' foo
Unsuccessful stat on filename containing newline at /usr/share/perl5/File/Rename.pm line 69.
~/tmp$ ls
foo?bar

答案4

这个问题的一个方面实际上与 shell 无关awk,而且只与 shell 有关。问题是,在标准的、规范的 tty 上,大多数时候内核的 tty 规则正在缓冲您的输入 - 只是将其回显到屏幕上,而不是其他地方 - 以便它可以有效地处理退格等。

但是,当您按回车键或以其他方式输入换行符时,所有缓冲的数据都会立即推送到读取应用程序 - 通常是您的 shell。您可以通过$PS2在输入悬空报价后进行观察来观察这一点。当 shell 打印时,$PS2这是因为它刚刚读取了您输入的某些块,但尚未确信您已完成。

因此,为了方便起见,您需要某种方法将\newline 发送到终端缓冲区,而不必立即推送所有其他输入。标准方法是使用按键序列CTRL+V- 哪个引号对于终端,您的下一个输入字符。做CTRL+V然后CTRL+J- 因为后者通常是如何键入文字\newline。当您看不到时,您就会知道它已经起作用,$PS2因为 shell 仍未读取您的输入。

但请注意,当它阅读您之前的输入CTRL+V对于 shell 来说根本没有任何区别 - 只是为了线路规则而引用它。您肯定还想用 shell 引用换行符来用它做任何有意义的事情。

顺便一提,CTRL+V可以以其他方式有效地应用 - 例如,"$(printf \\33)"这不是编写ESC将字符写入 shell 脚本 - 这甚至不是最简单的。如果您首先以这种方式转义它,您可以从字面上输入键盘将发送的任何字符,而无需输入驱动程序尝试解释它。

我经常喜欢在命令行上使用 <tab>,而不需要 shell 尝试完成任何操作。因为完成补全的 shell 通常会以与 相同的方式配置 <tab> stty eol \t,以使其补全系统正常工作,CTRL+V即使在陌生的环境中也对我有用。

相关内容