Tambahkan baris baru ke nama file dengan `mv`

11

Ini pertanyaan serius. Saya menguji beberapa awkskrip dan saya perlu file dengan baris baru di namanya.


Apakah mungkin menambahkan baris baru ke nama file mv?

Saya sekarang, saya bisa melakukan ini dengan touch:

touch "foo
bar"

Dengan sentuhan saya menambahkan karakter baris baru per salin dan tempel. Tapi saya tidak bisa menulis fooReturnbardi shell saya.

Bagaimana saya bisa mengganti nama file, untuk memiliki baris baru dalam nama file?


Edit 2015/06/28; 07:08 malam

Untuk menambahkan baris baru di zshsaya dapat menggunakan, Alt+Return

AB
sumber
2
Kenapa kamu bertanya? Apakah Anda bercanda atau menipu teman?
Basile Starynkevitch
2
Jangan hapus pertanyaan, ini berguna. Tapi sebisa mungkin hindari baris baru dalam nama file.
Basile Starynkevitch
2
Apa yang membuat Anda berpikir melakukannya dengan mvakan berbeda dari melakukannya dengan touch? Apakah Anda mencoba hal yang sama?
Kevin
2
Nah, Anda dapat menyalin dan menempel ke mvperintah semudah itu touch.
Kevin
2
Jadi izinkan saya menyarankan Anda untuk merumuskan lebih jelas OP Anda: Dalam lingkungan shell yang diberikan, saya tidak bisa mengetikkan baris baru dalam string yang dikutip seperti dalam gema "a [return] b".
dan

Jawaban:

22

Itu ide yang buruk (memiliki karakter aneh dalam nama file) tetapi Anda bisa melakukannya

 mv somefile.txt "foo
 bar"

(Anda bisa juga melakukan mv somefile.txt "$(printf "foo\nbar")"atau mv somefile.txt foo$'\n'bar, dll ... detail khusus untuk shell Anda. Saya menggunakan zsh)

Baca lebih lanjut tentang globbing , misalnya glob (7) . Detailnya bisa spesifik untuk shell. Tapi pahami yang /bin/mv diberikan (oleh shell Anda), melalui execve (2) , array argumen yang diperluas : ekspansi argumen dan globbing adalah tanggung jawab shell yang memanggil.

Dan Anda bahkan bisa membuat kode program C kecil untuk melakukan hal yang sama:

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

Simpan program di atas foo.c, kompilasi dengan gcc -Wall foo.c -o foo kemudian jalankan./foo

Demikian juga, Anda dapat membuat kode skrip yang serupa di Perl, Ruby, Python, Ocaml, dll ....

Tapi itu ide yang buruk. Hindari baris baru dalam nama file (itu akan membingungkan pengguna, dan itu bisa merusak banyak skrip).

Sebenarnya, saya bahkan merekomendasikan untuk menggunakan hanya huruf, angka, dan +-/._% karakter yang tidak ditekankan (dengan / menjadi pemisah direktori) dalam jalur file. File "tersembunyi" (dimulai dengan .) harus digunakan dengan hati-hati dan parcimony. Saya percaya menggunakan segala jenis ruang dalam nama file adalah kesalahan. Gunakan garis bawah sebagai gantinya (misalnya foo/bar_bee1.txt) atau minus (misalnya foo/bar-bee1.txt)

Basile Starynkevitch
sumber
Ya, saya tahu, bahwa saya dapat menyalin dan menempelkan karakter baris baru, tetapi bagaimana saya bisa melakukannya tanpa menyalin dan menempel?
AB
4
Tidak ada salinan atau tempel di sini. Setelah itu ada baris baru yang diketik foo.
dan
Namun itu berfungsi juga menyalin-menempelkannya
kos
1
Ini adalah ide yang buruk untuk file biasa, tetapi merupakan test case yang bagus, seperti yang disebutkan OP.
artdanil
5
@dan ,akan lebih berbahaya daripada -(seperti di posisi pertama) atau %. Semua rekomendasi tersebut terutama untuk mengatasi bug di beberapa aplikasi (yang memecah nama file yang dinyatakan valid dari sudut pandang OS). Rasanya terbelakang untuk meminta orang tidak menggunakan karakter itu daripada memperbaiki bug mereka.
Stéphane Chazelas
19

Jika Anda menggunakan bash, perintah ini akan berfungsi.

mv a $'b\nc'
favadi
sumber
4
Bekerja dengan zshjuga =)
AB
3
bash, seperti zsh dan FreeBSD sh menyalinnya dari ksh93.
Stéphane Chazelas
Terima kasih banyak! Saya benar-benar lupa tentang $ dalam bash, sementara itu adalah jawaban saya sendiri pada SO menasihati menggunakannya - stackoverflow.com/questions/1825552/grep-a-tab-in-unix/…
antimirov
6

Saya tahu Anda meminta mvsolusi, namun, meskipun ada peringatan, ini dapat dengan mudah dilakukan rename(dalam paket 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
kos
sumber
Terima kasih untuk rename, ide yang sangat bagus. +1
AB
5

Salah satu aspek dari masalah ini sebenarnya bukan tentang awk- dan hanya sedikit tentang shell. Masalahnya adalah bahwa pada standar, tty kanonik sebagian besar waktu disiplin tty kernel buffering input Anda - hanya menggemakannya ke layar Anda dan tempat lain - sehingga secara efisien dapat menangani backspacing dan sejenisnya.

Namun, ketika Anda menekan kembali atau memasukkan baris baru, semua data buffer didorong sekaligus ke aplikasi membaca - biasanya shell Anda. Anda dapat mengamati ini dengan memperhatikan $PS2setelah memasukkan penawaran yang menggantung. Ketika shell mencetaknya, $PS2itu karena ia baru saja membaca beberapa blok input Anda dan belum yakin Anda berhasil.

Jadi, untuk kenyamanan, yang Anda butuhkan adalah beberapa cara mengirimkan \newline ke buffer terminal tanpa harus mendorong semua input lainnya segera. Cara standar untuk melakukannya adalah dengan urutan-kunci CTRL+V- yang mengutip untuk terminal karakter input Anda selanjutnya. Apakah CTRL+Vkemudian CTRL+J- karena yang terakhir ini biasanya cara mengetik literal \newline. Anda akan tahu itu berfungsi ketika Anda tidak melihat $PS2karena shell masih belum membaca input Anda.

Catatan meskipun ketika tidak membaca bahwa masukan Anda sebelumnya CTRL+Vakan membuat perbedaan untuk shell sama sekali - yang hanya mengutip untuk garis-disiplin. Anda pasti ingin mengutip kutipan baris baru juga untuk melakukan sesuatu yang bermakna dengannya.

Ngomong-ngomong, CTRL+Vbisa diterapkan dengan cara lain - misalnya "$(printf \\33)"bukan satu-satunya cara untuk menulis ESCkarakter ke skrip shell - dan itu bahkan bukan yang paling sederhana. Anda benar-benar dapat memasukkan karakter apa pun yang akan dikirim papan ketik Anda tanpa driver input yang berusaha menerjemahkannya jika Anda baru saja menghindarinya dengan cara ini.

Saya sering suka menggunakan <tab> pada command-line tanpa shell berusaha untuk menyelesaikan apa pun. Karena shell yang melakukan penyelesaian biasanya akan mengkonfigurasi <tab> dengan cara yang sama stty eol \t, untuk membuat sistem penyelesaiannya bekerja, CTRL+Vbekerja untuk saya bahkan di lingkungan yang tidak dikenal.

mikeserv
sumber
2
Terima kasih telah menyebutkan 'Ctrl + V'. Saya akan mengirim jawaban tentang hal itu dan kemudian melihat penjelasan Anda.
artdanil