Додайте новий рядок до імені файлу за допомогою `mv`


11

Це серйозне питання. Я тестую деякі awkсценарії, і мені потрібні файли з новим рядком у їхніх назвах.


Чи можна додати новий рядок до імені файлу за допомогою mv?

Я зараз, я можу це зробити touch:

touch "foo
bar"

З дотиком я додав символ нового рядка за копію та вставлення. Але я не можу писати fooReturnbarу своїй оболонці.

Як я можу перейменувати файл, щоб у назві файла був новий рядок?


Редагувати 2015/06/28; 07:08 вечора

Щоб додати новий рядок у zshя можу використовувати, Alt+Return


2
Чому ти питаєш? Ви робите якийсь жарт чи хитрість другові?
Базиль Старинкевич

2
Не знімайте питання, це корисно. Але дійсно уникайте нових рядків у назви файлів якомога більше.
Базиль Старинкевич

2
Чому ви думаєте, чи mvбуде це робити, чим відрізняється від цього touch? Ви пробували те саме?
Кевін

2
Ну, ви можете скопіювати та вставити в mvкоманду так само легко, як і touch.
Кевін

2
Тож дозвольте запропонувати вам більш чітко сформулювати свою ОП: У заданому середовищі оболонки я не можу набрати новий рядок у цитованому рядку, як у відголосі "a [return] b".
дан

Відповіді:


22

Це погана ідея (мати дивні символи у назвах файлів), але ви могли б зробити

 mv somefile.txt "foo
 bar"

(Ви також могли зробити mv somefile.txt "$(printf "foo\nbar")"або mv somefile.txt foo$'\n'bar, і т. д. ... деталі конкретні для вашої оболонки. Я використовую zsh)

Детальніше про глобалізацію , наприклад, 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.
дан

Однак це також працює, скопіювавши його
kos

1
Це погана ідея для звичайних файлів, але хороший тестовий випадок, як згадував ОП.
artdanil

5
@і ,були б більш нешкідливими, ніж -(як у першій позиції) чи %. Усі ці рекомендації в основному полягають у вирішенні помилок у деяких програмах (які розбиваються на імена файлів, які в іншому випадку дійсні з точки зору ОС). Зворотно просити людей не використовувати цих символів, а не виправляти помилки.
Стефан Шазелас

19

Якщо ви використовуєте bash, ця команда повинна працювати.

mv a $'b\nc'

4
Працює з zshтакож =)
AB

3
bash, як zsh і FreeBSD sh скопіювали це з ksh93.
Стефан Шазелас

Дуже дякую! Я зовсім забув про $ в Баш, в той час як це був мій власний відповідь на SO радячи використовувати його - stackoverflow.com/questions/1825552/grep-a-tab-in-unix / ...
Антисвіти

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 більшу частину часу чітка дисципліна ядра буферизує ваш вклад - просто повторюючи його на ваш екран і ніде більше - щоб воно могло ефективно обробляти зворотні розміри та подібні.

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

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

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

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

Мені часто подобається використовувати <tab> s в командному рядку без оболонки, намагаючись нічого завершити. Оскільки оболонки, які завершують завершення, зазвичай налаштовують <tab> так stty eol \t, щоб вони працювали в системах завершення,CTRL+V навіть у незнайомих середовищах .


2
Дякуємо, що згадали про "Ctrl + V". Я збирався розмістити відповідь на це, а потім побачив ваше пояснення.
artdanil
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.