Adiciona uma nova linha em um nome de arquivo com 'mv'

10

É uma questão séria. Eu testo alguns scripts de awk e preciso de arquivos com uma nova linha em seus nomes.

É possível adicionar uma nova linha em um nome de arquivo com mv ?

Eu agora posso fazer isso com touch :

touch "foo
bar"

Com o toque, adicionei o caractere de nova linha por cópia e colagem. Mas não consigo escrever foo Retornar bar no meu shell.

Como posso renomear um arquivo para ter uma nova linha no nome do arquivo?

Editar 2015/06/28; 07:08 pm

Para adicionar uma nova linha em zsh eu posso usar, Alt + Retornar

    
por A.B. 28.06.2015 / 13:00

4 respostas

21

É uma má idéia (ter caracteres estranhos em nomes de arquivos), mas você pode fazer

 mv somefile.txt "foo
 bar"

(você também pode ter feito mv somefile.txt "$(printf "foo\nbar")" ou mv somefile.txt foo$'\n'bar , etc ... detalhes são específicos do seu shell. Estou usando zsh )

Leia mais sobre globbing , por exemplo glob (7) . Detalhes podem ser específicos do shell. Mas entenda que /bin/mv é dado (pelo seu shell), via execve (2) , uma matriz expandida de argumentos: expansão de argumento e globbing é responsabilidade do shell de chamada.

E você pode até codificar um minúsculo programa em C para fazer o mesmo:

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

Salve o programa acima em foo.c , compile-o com gcc -Wall foo.c -o foo e execute ./foo

Da mesma forma, você pode codificar um script semelhante em Perl, Ruby, Python, Ocaml, etc ....

Mas isso é uma má ideia. Evite novas linhas em nomes de arquivos (isso confundirá o usuário e poderá quebrar muitos scripts).

Na verdade, até recomendo usar apenas letras não acentuadas, dígitos e +-/._% caracteres (com / sendo o separador de diretório) nos caminhos de arquivo. Arquivos "ocultos" (começando com . ) devem ser usados com cautela e parcimônia. Eu acredito que usar qualquer tipo de espaço em um nome de arquivo é um erro. Use um sublinhado (por exemplo, foo/bar_bee1.txt ) ou menos (por exemplo, foo/bar-bee1.txt )

    
por 28.06.2015 / 13:05
17

Se você usar o bash, este comando deve funcionar.

mv a $'b\nc'
    
por 28.06.2015 / 13:09
6

Eu sei que você pediu por uma solução mv , no entanto, apesar do aviso, isso pode ser feito facilmente com rename (no pacote 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
    
por 28.06.2015 / 13:12
5

Um aspecto deste problema não é realmente sobre awk - e apenas um pouco sobre o shell. O problema é que, na maioria das vezes, a disciplina tty do kernel está armazenando em buffer sua entrada - apenas fazendo eco para sua tela e em nenhum outro lugar - para que possa lidar eficientemente com backspacing e coisas do tipo.

No entanto, quando você pressiona return ou insere uma nova linha, todos esses dados armazenados em buffer são enviados ao aplicativo de leitura - geralmente seu shell. Você pode observar isso observando $PS2 após inserir uma cotação pendente. Quando o shell imprime $PS2 , é porque acabou de ler um bloco de sua entrada e ainda não está convencido de que você acabou de passar.

Portanto, por conveniência, o que você precisa é de alguma maneira de enviar um \n ewline para o buffer de terminal sem ter que empurrar todas as outras entradas imediatamente. A maneira padrão de fazer isso é com a sequência de chaves CTRL+V - que aspas para o terminal do seu próximo caractere de entrada. Do > CTRL+V , em seguida, CTRL+J - porque o último é geralmente como digitar um literal \n ewline. Você saberá que funcionou quando você não vê $PS2 porque o shell ainda não leu sua entrada.

Note que quando faz ler aquela entrada, o CTRL+V anterior não terá feito nenhuma diferença para o shell - que apenas o cita para o line- disciplina. Você definitivamente vai querer citar a nova linha também para fazer qualquer coisa significativa com ela.

A propósito, CTRL+V pode ser aplicado de outras maneiras - por exemplo, "$(printf \33)" não é a única maneira de escrever um caracter ESC em um script de shell - e nem é o mais simples. Você pode literalmente digitar qualquer caractere que seu teclado enviará sem que o driver de entrada tente interpretá-lo se você simplesmente escapar dessa maneira.

Eu geralmente gosto de usar < tab > s na linha de comando sem o shell tentar concluir qualquer coisa. Como os shells que fazem a conclusão normalmente configuram < tab > de certa forma, sinônimo de stty eol \t , para fazer seus sistemas de completamento funcionarem, CTRL+V funciona para mim mesmo em ambientes desconhecidos.

    
por 29.06.2015 / 08:12