Thêm một dòng mới vào một tên tệp với `mv`


11

Đây là một câu hỏi nghiêm túc. Tôi kiểm tra một số awktập lệnh và tôi cần các tập tin với một dòng mới trong tên của chúng.


Có thể thêm một dòng mới vào một tên tệp với mv?

Tôi bây giờ, tôi có thể làm điều này với touch:

touch "foo
bar"

Với cảm ứng tôi đã thêm ký tự dòng mới trên mỗi bản sao và dán. Nhưng tôi không thể viết fooReturnbarvào vỏ của mình.

Làm cách nào để đổi tên tệp, để có dòng mới trong tên tệp?


Chỉnh sửa 2015/06/28; 07:08 tối

Để thêm một dòng mới trong zshtôi có thể sử dụng, Alt+Return


2
Tại sao bạn hỏi Bạn đang thực hiện một số trò đùa hoặc lừa cho một người bạn?
Basile Starynkevitch

2
Đừng xóa câu hỏi, nó rất hữu ích. Nhưng thực sự tránh các dòng mới trong tên tệp càng nhiều càng tốt.
Basile Starynkevitch

2
Điều gì khiến bạn nghĩ rằng làm nó với mvsẽ khác với làm với nó touch? Bạn đã thử điều tương tự?
Kevin

2
Vâng, bạn có thể sao chép và dán vào mvlệnh dễ dàng như touch.
Kevin

2
Vì vậy, để tôi đề nghị bạn xây dựng rõ ràng hơn OP của bạn: Trong một môi trường shell nhất định, tôi không thể nhập một dòng mới trong một chuỗi được trích dẫn như trong tiếng vang "a [return] b".
dan

Câu trả lời:


22

Đó là một ý tưởng tồi (để có các ký tự lạ trong tên tệp) nhưng bạn có thể làm

 mv somefile.txt "foo
 bar"

(bạn cũng có thể đã thực hiện mv somefile.txt "$(printf "foo\nbar")"hoặc mv somefile.txt foo$'\n'bar, v.v ... chi tiết cụ thể cho vỏ của bạn. Tôi đang sử dụng zsh)

Tìm hiểu thêm về Globing , ví dụ toàn cầu (7) . Thông tin chi tiết có thể là vỏ cụ thể. Nhưng hiểu rằng /bin/mv được đưa ra (bởi shell của bạn), qua execve (2) , một mở rộng mảng các đối số: mở rộng đối số và globbing là trách nhiệm của vỏ cách gọi.

Và bạn thậm chí có thể mã hóa một chương trình C nhỏ để làm điều tương tự:

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

Lưu chương trình trên vào foo.c, biên dịch nó với gcc -Wall foo.c -o foo rồi chạy./foo

Tương tự như vậy, bạn có thể mã một tập lệnh tương tự trong Perl, Ruby, Python, Ocaml, v.v ....

Nhưng đó là một ý tưởng tồi. Tránh các dòng mới trong tên tệp (nó sẽ gây nhầm lẫn cho người dùng và nó có thể phá vỡ nhiều tập lệnh).

Trên thực tế, tôi thậm chí khuyên bạn chỉ nên sử dụng các chữ cái, chữ số và +-/._% ký tự không có dấu (với / dấu phân cách thư mục) trong đường dẫn tệp. Các tập tin "ẩn" (bắt đầu bằng .) nên được sử dụng một cách thận trọng và parcimony. Tôi tin rằng việc sử dụng bất kỳ loại không gian nào trong tên tệp là một sai lầm. Sử dụng dấu gạch dưới thay thế (ví dụ foo/bar_bee1.txt) hoặc dấu trừ (ví dụ foo/bar-bee1.txt)


Vâng, tôi biết, rằng tôi có thể sao chép và dán một ký tự dòng mới, nhưng làm thế nào tôi có thể làm điều đó mà không cần sao chép và dán?
AB

4
Không có bất kỳ bản sao hoặc dán ở đây. Có một dòng mới đánh máy sau foo.
dan

Tuy nhiên, nó cũng hoạt động sao chép nó
kos

1
Đó là một ý tưởng tồi cho các tệp thông thường, nhưng là một trường hợp thử nghiệm tốt, như OP đã đề cập.
artdanil

5
@,sẽ vô hại hơn -(như ở vị trí đầu tiên) hoặc %. Tất cả những đề xuất đó chủ yếu là để khắc phục lỗi trong một số ứng dụng (phá vỡ tên tệp có giá trị khác theo quan điểm của HĐH). Nó cảm thấy lạc hậu khi yêu cầu mọi người không sử dụng các ký tự đó hơn là sửa các lỗi của họ.
Stéphane Chazelas


6

Tôi biết bạn đã yêu cầu một mvgiải pháp, tuy nhiên, bất chấp cảnh báo, điều này có thể dễ dàng thực hiện với rename(trong gói 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

Cảm ơn bạn cho rename, một ý tưởng rất tốt. +1
AB

5

Một khía cạnh của vấn đề này không thực sự là về awk- và chỉ một chút về vỏ. Vấn đề là ở một tiêu chuẩn, kinh điển, hầu hết thời gian, kỷ luật tty của kernel đang đệm đầu vào của bạn - chỉ cần lặp lại nó trên màn hình của bạn và không ở đâu khác - để nó có thể xử lý hiệu quả khoảng cách và tương tự.

Tuy nhiên, khi bạn nhấn return hoặc nhập một dòng mới, tất cả dữ liệu được đệm đó sẽ được đẩy cùng lúc vào ứng dụng đọc - thường là vỏ của bạn. Bạn có thể quan sát điều này bằng cách xem $PS2sau khi nhập một trích dẫn lơ lửng. Khi trình bao in ra $PS2, vì nó chỉ đọc một số khối đầu vào của bạn và chưa thuyết phục bạn thông qua.

Vì vậy, để thuận tiện, những gì bạn cần là một số cách gửi \newline vào bộ đệm đầu cuối mà không phải đẩy tất cả các đầu vào khác ngay lập tức. Cách tiêu chuẩn để làm như vậy là w / chuỗi khóa CTRL+V- trích dẫn cho thiết bị đầu cuối ký tự đầu vào tiếp theo của bạn. Làm CTRL+Vsau đó CTRL+J- bởi vì sau này thường là làm thế nào để gõ một \newline theo nghĩa đen . Bạn sẽ biết nó hoạt động khi bạn không nhìn thấy $PS2vì trình bao vẫn chưa đọc dữ liệu nhập của bạn.

Lưu ý rằng mặc dù khi nó không đọc mà đầu vào của bạn trước đó CTRL+Vsẽ đã có sự khác biệt cho vỏ ở tất cả - mà chỉ trích nó cho dòng kỷ luật. Bạn chắc chắn sẽ muốn trích dẫn dòng mới cũng như làm bất cứ điều gì có ý nghĩa với nó.

Nhân tiện, CTRL+Vcó thể được áp dụng một cách hữu ích theo những cách khác - ví dụ "$(printf \\33)"không phải là cách duy nhất để viết một ESCký tự vào tập lệnh shell - và nó thậm chí không đơn giản nhất. Bạn có thể nhập bất kỳ ký tự nào mà bàn phím của bạn sẽ gửi mà không cần trình điều khiển đầu vào cố gắng diễn giải nó nếu bạn lần đầu tiên thoát nó theo cách này.

Tôi thường thích sử dụng <tab> s trên dòng lệnh mà không cần trình bao cố gắng hoàn thành bất cứ điều gì. Bởi vì các shell hoàn thành thường sẽ cấu hình <tab> theo cách đồng nghĩa với stty eol \t, để làm cho các hệ thống hoàn thành của chúng hoạt động, CTRL+Vhoạt động với tôi ngay cả trong các môi trường xa lạ.


2
Cảm ơn bạn đã đề cập đến 'Ctrl + V'. Tôi đã định đăng câu trả lời về nó và sau đó thấy lời giải thích của bạn.
artdanil
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.