这是一个严肃的问题。我测试了一些awk
脚本,并且需要名称中带有换行符的文件。
是否可以使用 向文件名添加换行符mv
?
我现在可以这样做touch
:
touch "foo
bar"
通过触摸,我在每次复制和粘贴时添加了换行符。但我无法foo
Returnbar
在 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
这是因为它刚刚读取了您输入的某些块,但尚未确信您已完成。
因此,为了方便起见,您需要某种方法将\n
ewline 发送到终端缓冲区,而不必立即推送所有其他输入。标准方法是使用按键序列CTRL+V
- 哪个引号对于终端,您的下一个输入字符。做CTRL+V
然后CTRL+J
- 因为后者通常是如何键入文字\n
ewline。当您看不到时,您就会知道它已经起作用,$PS2
因为 shell 仍未读取您的输入。
但请注意,当它做阅读您之前的输入CTRL+V
对于 shell 来说根本没有任何区别 - 只是为了线路规则而引用它。您肯定还想用 shell 引用换行符来用它做任何有意义的事情。
顺便一提,CTRL+V
可以以其他方式有效地应用 - 例如,"$(printf \\33)"
这不是编写ESC
将字符写入 shell 脚本 - 这甚至不是最简单的。如果您首先以这种方式转义它,您可以从字面上输入键盘将发送的任何字符,而无需输入驱动程序尝试解释它。
我经常喜欢在命令行上使用 <tab>,而不需要 shell 尝试完成任何操作。因为完成补全的 shell 通常会以与 相同的方式配置 <tab> stty eol \t
,以使其补全系统正常工作,CTRL+V
即使在陌生的环境中也对我有用。