Добавьте новую строку в имя файла с помощью `mv`

11

Это серьезный вопрос. Я тестирую некоторые awkскрипты и мне нужны файлы с новой строкой в ​​их именах.


Можно ли добавить новую строку в имя файла с mv?

Теперь я могу сделать это с touch:

touch "foo
bar"

С прикосновением я добавил символ новой строки для каждой копии и вставки. Но я не могу написать fooReturnbarв своей оболочке.

Как я могу переименовать файл, чтобы иметь новую строку в имени файла?


Изменить 2015/06/28; 07:08

Чтобы добавить новую строку в zshя могу использовать, Alt+Return

AB
источник
2
Почему вы спрашиваете? Вы шутите или подшучиваете над другом?
Василий Старынкевич
2
Не снимайте вопрос, это полезно. Но по возможности избегайте новых строк в именах файлов.
Василий Старынкевич
2
Что заставляет вас думать, что делать это mvбудет чем-то отличным от этого touch? Вы пробовали то же самое?
Кевин
2
Ну, вы можете скопировать и вставить в mvкоманду так же легко, как touch.
Кевин
2
Итак, позвольте мне предложить вам более четко сформулировать ваш ОП: В данной оболочке я не могу набирать символ новой строки внутри строки в кавычках, как в echo "a [return] b".
Дан

Ответы:

22

Это плохая идея (иметь странные символы в именах файлов), но вы могли бы сделать

 mv somefile.txt "foo
 bar"

(вы могли бы также сделать mv somefile.txt "$(printf "foo\nbar")"или mv somefile.txt foo$'\n'bar, и т. д. ... подробности специфичны для вашей оболочки. Я использую zsh)

Узнайте больше о globbing , например glob (7) . Детали могут быть специфичными для оболочки. Но поймите, что /bin/mv (с помощью вашей оболочки) через execve (2) предоставляется расширенный массив аргументов: расширение и глобализация аргументов является обязанностью вызывающей оболочки.

И вы могли бы даже написать крошечную 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)

Василий Старынкевич
источник
Да, я знаю, что могу скопировать и вставить символ новой строки, но как я могу это сделать без копирования и вставки?
AB
4
Здесь нет ни одной копии или вставки. После этого вводится новая строка foo.
Дан
Тем не менее, он работает и копировать его
Кос
1
Это плохая идея для обычных файлов, но хороший тестовый пример, как упоминалось в ОП.
Артданил
5
@и ,будет более безобидным, чем -(как в первой позиции) или %. Все эти рекомендации предназначены главным образом для устранения ошибок в некоторых приложениях (которые нарушают имена файлов, которые в противном случае действительны с точки зрения ОС). Мне кажется обратным просить людей не использовать этих персонажей вместо того, чтобы исправлять их ошибки.
Стефан Шазелас
19

Если вы используете bash, эта команда должна работать.

mv a $'b\nc'
favadi
источник
4
Также работает с zsh=)
AB
3
bash, как zsh и FreeBSD sh скопировал это из ksh93.
Стефан Шазелас
Большое спасибо! Я полностью забыл про $ in bash, хотя это был мой собственный ответ на SO, советовавший использовать его - stackoverflow.com/questions/1825552/grep-a-tab-in-unix/…
antimirov
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-дисциплина ядра буферизует ваш ввод - просто выводит его на экран и больше нигде - так, чтобы он мог эффективно обрабатывать возврат и тому подобное.

Однако, когда вы нажимаете return или иным образом вводите новую строку, все эти буферизованные данные сразу передаются в приложение для чтения - обычно в вашу оболочку. Вы можете наблюдать это, наблюдая за $PS2введением висячей цитаты. Когда оболочка печатает, $PS2это потому, что она просто читает какой-то блок вашего ввода и еще не убеждена, что вы прошли.

Итак, для удобства вам нужен какой-то способ отправки \newline в буфер терминала без необходимости немедленной отправки всех этих других входных данных. Стандартный способ сделать это - w / последовательность клавиш CTRL+V- которая указывает на терминал ваш следующий вводимый символ. Сделайте CTRL+Vтогда CTRL+J- потому что последнее обычно, как печатать буквальный \newline. Вы будете знать, что это работает, когда вы не видите, $PS2потому что оболочка все еще не прочитала ваш ввод.

Обратите внимание , однако , что , когда он действительно читал , что ваш вход раньше CTRL+Vне будет никакой разницы для оболочки вообще - что только цитирует его линию дисциплины. Вы определенно захотите заключить в кавычки новую строку, чтобы сделать с ней что-нибудь значимое.

Кстати, CTRL+Vможет быть с пользой применен другими способами - например, "$(printf \\33)"это не единственный способ записать ESCсимвол в сценарий оболочки - и он даже не самый простой. Вы можете буквально ввести любой символ, который будет отправлять ваша клавиатура, без попытки драйвера ввода интерпретировать его, если вы просто экранируете его таким образом.

Мне часто нравится использовать <tab> в командной строке, а оболочка не пытается что-либо завершить. Поскольку оболочки, выполняющие завершение, обычно настраивают <tab> таким образом stty eol \t, чтобы их системы завершения работали, это CTRL+Vработает для меня даже в незнакомой среде.

mikeserv
источник
2
Спасибо за упоминание Ctrl + V. Я собирался опубликовать ответ об этом, а затем увидел ваше объяснение.
Артданил