用`mv`将换行符添加到文件名中


11

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


是否可以使用来在文件名中添加换行符mv

我现在可以用touch

touch "foo
bar"

通过触摸,我为每个副本和粘贴添加了换行符。但是我不能fooReturnbar在shell中写。

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


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

要添加换行符,zsh我可以使用Alt+Return


2
你为什么要问?您是在和朋友开玩笑吗?
Basile Starynkevitch

2
不要删除问题,这很有用。但实际上应尽可能避免在文件名中使用换行符。
Basile Starynkevitch

2
是什么让您认为使用此方法与使用它有mv什么不同touch?你尝试过同样的事情吗?
凯文(Kevin)

2
好了,您可以mv像一样轻松地将其复制并粘贴到命令中touch
凯文

2
因此,让我建议您更清楚地描述您的OP:在给定的shell环境中,我无法像在echo“ a [return] b”中那样在带引号的字符串中键入换行符。
2015年

Answers:


22

这是一个坏主意(文件名中包含奇怪的字符),但是您可以

 mv somefile.txt "foo
 bar"

(您也可能已经完成mv somefile.txt "$(printf "foo\nbar")"mv somefile.txt foo$'\n'bar,等等。。。细节是特定于您的shell的。我正在使用zsh

阅读有关globing的更多信息,例如glob(7)。详细信息可能是特定于外壳的。但是请理解,这/bin/mv 是通过execve(2)(由您的Shell给出)的,它是一个扩展的参数数组:参数扩展和globlob是调用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.cgcc -Wall foo.c -o foo 然后编译运行./foo

同样,您可以在Perl,Ruby,Python,Ocaml等中编写类似的脚本。

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

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


是的,我知道可以复制和粘贴换行符,但是如果不复制和粘贴怎么办?
AB

4
这里没有任何副本或粘贴。后面有一个换行符foo
2015年

但是它也可以复制粘贴
kos 2015年

1
正如OP所提到的,对于普通文件来说这是一个坏主意,但对于测试案例却是一个很好的测试。
artdanil

5
@并且,-(例如处于第一位置)或更加无害%。所有这些建议主要是为了解决某些应用程序中的错误(这些错误会破坏文件名,这些文件名从OS角度来看是有效的)。要求人们不要使用这些字符而不是修复其错误感觉很落后。
斯特凡Chazelas


6

我知道您要求一个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

谢谢您的支持rename,这是一个非常好的主意。+1
AB

5

这个问题的一个方面并不是真的awk-只是关于外壳的一小部分。问题在于,在大多数情况下,在标准的规范tty中,内核的tty准则会缓冲您的输入-只是将其回显到屏幕上,而没有其他地方-以便它可以有效地处理退格等问题。

但是,当您按回车键或以其他方式输入换行符时,所有缓冲的数据将立即推送到读取应用程序-通常是您的shell。您可以$PS2在输入悬空的报价后进行观察,以进行观察。当shell打印时$PS2,是因为它只是读取了您的输入的一部分而还没有说服您通过。

因此,为方便起见,您需要的是一种将\newline 发送到终端缓冲区的方法,而不必立即推送所有其他输入。这样做的标准方法是使用键序列CTRL+V-该键在终端上引用您的下一个输入字符。不要CTRL+V那么CTRL+J-因为后者通常是如何键入文字\newline。当您看不到它时,您会知道它是有效的,$PS2因为shell仍未读取您的输入。

不过,请注意,当它读取输入你刚才CTRL+V会已经为壳没有什么区别的话-只有引用它的线路规程。您当然也想用shell引用换行符,以便对它进行有意义的操作。

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

我经常喜欢在命令行上使用<tab>,而shell不会尝试完成任何事情。因为完成stty eol \t补全的shell通常会以与等同的方式配置<tab> ,以使补全系统正常工作,CTRL+V即使在不熟悉的环境中,它们也对我有效。


2
感谢您提及“ Ctrl + V”。我正要发布有关此问题的答案,然后看到您的解释。
artdanil
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.