chắp thêm văn bản với tiếng vang mà không có dòng mới


14

Tôi muốn nối văn bản vào tập tin như thế nào echo "abc" >>file.txt.

Nhưng điều này thêm abcsau dòng mới

Làm thế nào tôi có thể thêm abcvào cuối tập tin với echo mà không có dòng mới?


2
Các tập tin đã có một dòng mới, bạn chỉ cần thêm sau nó. Vì vậy, bạn sẽ phải thay thế ký tự dòng mới từ dòng cuối cùng, với abc abc.
ctrl-alt-delor

Chào mừng bạn đến với StackExchange! Câu hỏi của bạn là tốt; sẽ tốt hơn nếu bạn chỉ định các ví dụ về nội dung của tệp của bạn (trước khi thêm, những gì bạn nhận được sau khi thêm, thay vào đó bạn muốn gì). Tôi nói điều này bởi vì một trong những câu trả lời là làm thế nào để thêm abcmà không có dòng mới cuối cùng, mà (sau khi đọc câu hỏi của bạn một cách chăm chú) dường như không phải là điều bạn muốn.
Luật29

Câu trả lời:


19

echo "abc" >>file.txtđặt một dòng mới sau abc , không phải trước. Nếu bạn kết thúc với abcdòng riêng của mình, điều đó có nghĩa là dòng mới trước abcđó đã có mặt file.txt.

Lưu ý rằng việc tệp văn bản kết thúc ở dòng mới là hoàn toàn bình thường. Trên unix, một dòng bao gồm một chuỗi các ký tự không phải là null⁰ hoặc dòng mới theo sau là một dòng mới. 1 Do đó, mọi tệp văn bản không trống đều kết thúc bằng ký tự dòng mới.

Nếu bạn muốn thêm văn bản vào dòng cuối cùng của tệp, thì bạn không thể thực hiện được >>, bởi vì điều này luôn luôn nối với tệp, vì vậy nó luôn ghi sau dòng mới nhất. Thay vào đó, bạn cần một công cụ có khả năng sửa đổi một tập tin hiện có. Ví dụ: bạn có thể sử dụng sed :

sed '$ s/$/abc/' file.txt >file.txt.new && mv file.txt.new file.txt

Trong lệnh sed, lệnh đầu tiên $có nghĩa là chỉ thực hiện lệnh sau trên dòng cuối cùng, lệnh s/REGEX/REPLACEMENT/thay thế REGEX bằng REPLACEMENT và biểu thức chính quy $khớp ở cuối dòng.

Lệnh sed của Linux có một tính năng tích hợp để tự động hóa trình tự tạo và thay thế tệp mới này, do đó bạn có thể rút ngắn điều đó thành

sed -i '$ s/$/abc/' file.txt

Đó là một byte null, mà ASCII gọi NUL và Unicode gọi U + 0000. Các chương trình xử lý văn bản có thể hoặc không thể đối phó với ký tự này.
1 Xem các định nghĩa về tệp văn bản , dòngký tự dòng mới trong phần "Định nghĩa" của chương Định nghĩa cơ sở của IEEE 1003.1-2008: 2016.


2
Là đoạn thứ hai của bạn có nghĩa là một tệp không kết thúc bằng một dòng mới không phải là một tệp văn bản? Ví dụ: nếu tôi lấy tệp văn bản ASCII hiện có kết thúc bằng một dòng mới và nối thêm một byte đơn 0x41(ASCII 'A'), về mặt kỹ thuật đó không còn là tệp văn bản? Nếu vậy, tôi khuyên bạn nên nhấn mạnh điểm đó vì đó là một định nghĩa không trực quan; nếu không, một sự thay đổi nhỏ trong cách diễn đạt có thể giúp tránh sự nhầm lẫn.
David Z

2
@DavidZ: Đó là định nghĩa chuẩn của tệp văn bản trong Unixland. IIRC nó thậm chí còn ở POSIX ở đâu đó.
Kevin

1
@Kevin Thú vị, tôi chưa bao giờ nghe điều đó trước đây. Chà, ngay cả khi nó là tiêu chuẩn, tôi nghĩ nó không trực quan.
David Z

15

Tôi không nghĩ rằng nó có thể với echolệnh, sedthay vào đó hãy sử dụng cách tiếp cận sau :

sed -i '$ s/$/abc/' file.txt
  • -i- sửa đổi các tập tin inplace
  • $ - cho biết bản ghi / dòng cuối cùng
  • s/$/abc/- thay thế cuối dòng $bằng chuỗi con abc(cho bản ghi cuối cùng)

2
Lưu ý rằng "tại chỗ" không thực sự có nghĩa là tại chỗ. Nó có nghĩa là "ghi nội dung đã chỉnh sửa vào một tệp có tên tạm thời bên cạnh tệp hiện có và sau đó thay thế nó". Bạn có thể chứng minh điều này bằng cách nhìn vào các nút vớidate >file; ls -i file; sed -i 's/201/ZZZ/' file; ls -i file
roaima

@roaima, tôi biết về sed thay đổi số inode.
RomanPerekhrest

2
Tôi nghĩ bạn sẽ có được, nhưng tôi lo ngại rằng với sự nhấn mạnh lại inplace đêm OP nghĩ rằng nó có thể được sử dụng để tránh đôi đĩa sử dụng không gian, ví dụ như với một file lớn.
roaima

@roaima, đêm nghĩ -> có thể nghĩ ...
RomanPerekhrest

13

Giả sử rằng tệp chưa kết thúc ở một dòng mới và bạn chỉ muốn thêm một số văn bản mà không cần thêm một, bạn có thể sử dụng -nđối số, ví dụ:

echo -n "some text here" >> file.txt

Tuy nhiên, một số hệ thống UNIX không cung cấp tùy chọn này; nếu đó là trường hợp bạn có thể sử dụng printf, vd

printf %s "some text here" >> file.txt

( %sđối số ban đầu là để bảo vệ chống lại văn bản bổ sung có các %ký tự định dạng trong đó)

Từ man echo(trên macOS High Sierra):

-n

Không in ký tự dòng mới. Điều này cũng có thể đạt được bằng cách nối thêm '\c'vào cuối chuỗi, như được thực hiện bởi các hệ thống tương thích iBCS2. Lưu ý rằng tùy chọn này cũng như ảnh hưởng của '\c'việc triển khai được xác định trong IEEE Std 1003.1-2001 ("POSIX.1") như được sửa đổi bởi Cor. 1-2002. Các ứng dụng hướng đến tính di động tối đa được khuyến khích sử dụng printf(1)để triệt tiêu ký tự dòng mới.


Nó khá rõ ràng là không kết thúc với một dòng mới. echo -nsẽ không có dòng mới nào ở cuối abc, nhưng abcvẫn sẽ được đặt trước dòng mới, đó là điều người dùng muốn tránh.
Kusalananda

@Kusalananda Câu trả lời của tôi đã được sử dụng nhiều hơn với giả định rằng OP sẽ cố gắng thay đổi quy trình của họ sao cho giả mạo \nkhông xuất hiện ở nơi đầu tiên. Nhiều tùy chọn sẽ tốt hơn, đặc biệt là khi chúng không liên quan đến việc phải viết lại toàn bộ tệp mỗi khi có thay đổi (có thể khá chậm và chạy trong thời gian đa thức nếu việc đó được thực hiện nhiều lần).
lông mịn

9

Nếu bạn có truncatelệnh và tệp văn bản của bạn có NL là ký tự cuối cùng của nó, bạn có thể xóa nó và sau đó nối thêm văn bản của bạn như sau:

truncate --size -1 file.txt
echo "abc" >>file.txt

(Lưu ý rằng truncatequan tâm gì về nội dung tập tin, và trong ví dụ này chỉ đơn giản là làm giảm kích thước tập tin bằng một byte. Nếu ký tự cuối cùng của bạn không phải là một byte duy nhất, tức là nó là một đa-byte "rộng" nhân vật sau đó bạn sẽ giới thiệu tham nhũng.)


5

Những gì bạn muốn là thêm nó ở cuối dòng cuối cùng, vì vậy ngay trước dấu phân cách của dòng cuối cùng, vì vậy ngay trước ký tự cuối cùng của tệp.

Với ksh93, bạn có thể làm:

echo abc 1<> file >#((EOF - 1))

Trường hợp 1<>toán tử chuẩn mở tệp ở chế độ đọc + ghi (và quan trọng hơn là không cắt ngắn ) trên thiết bị xuất chuẩn và >#((...))là toán tử tìm kiếm cụ thể ksh93 (ở đây để tìm kiếm trước byte cuối cùng). Lưu ý rằng echoviết abc<newline>nơi aghi đè lên dòng mới đã có và echothêm dòng mới của riêng nó.

Các zshtương đương:

zmodload zsh/system
{sysseek -w end -u 1 -1 && echo abc} 1<> file

Mặc dù để tương đương chính xác hơn, bạn cũng cần in thông báo lỗi khi không tìm kiếm:

zmodload zsh/system
if sysseek -w end -u 1 -1; then
  echo abc
else
  syserror -p "$0: $LINENO: seek: "
fi 1<> file

-1

Có thể là một UUOC nhưng bạn cũng có thể làm:

echo "$(cat file.txt)abc" >file.txt

Như Gilles chỉ ra lệnh này bị hạn chế:

Điều này chủ yếu hoạt động, nhưng không phải nếu đôi khi có một dòng trống ở cuối tập tin và một dòng trống ngay trước đó. Ví dụ: một tệp có số dòng cố định, trong đó dòng cuối cùng trống và được kéo dài theo thời gian và dòng tiếp theo có thể đôi khi trống.

Ngoài ra, hãy cảnh giác khi sử dụng cattrên các tệp mà bạn không quen thuộc:

Kết luận :

Sử dụng sed


2
Điều này chủ yếu hoạt động, nhưng không phải nếu đôi khi có một dòng trống ở cuối tập tin và một dòng trống ngay trước đó. Ví dụ: một tệp có số dòng cố định, trong đó dòng cuối cùng trống và được kéo dài theo thời gian và dòng tiếp theo có thể đôi khi trống.
Gilles 'SO- ngừng trở nên xấu xa'

Tôi có nên xóa nó? Tôi chắc chắn nghĩ rằng Roman / câu trả lời của bạn là cách phù hợp để đi nhưng tôi biết cá nhân tôi thích nhìn thấy các lựa chọn thay thế, và OP đã yêu cầu echo: p
jesse_b

1
Ngoài ra, điều này đặt toàn bộ tệp trên dòng lệnh
n.caillou

@ n.caillou hả? Điều này sẽ không in bất cứ điều gì để STDOUT.
jesse_b

2
Chà, không có lỗ hổng nào trong số đó thực sự liên quan đến cat, nhưng với các vấn đề với các chuỗi thoát tùy ý được gửi đến thiết bị đầu cuối.
ilkkachu
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.