Tôi có một tập tin foo.txt
, chứa các dòng sau:
a
b
c
Tôi muốn một lệnh đơn giản dẫn đến nội dung của foo.txt
:
a
b
Tôi có một tập tin foo.txt
, chứa các dòng sau:
a
b
c
Tôi muốn một lệnh đơn giản dẫn đến nội dung của foo.txt
:
a
b
Câu trả lời:
Sử dụng GNU sed
:
sed -i '$ d' foo.txt
Các -i
tùy chọn không tồn tại trong GNU sed
các phiên bản cũ hơn 3,95, vì vậy bạn phải sử dụng nó như một bộ lọc với một tập tin tạm thời:
cp foo.txt foo.txt.tmp
sed '$ d' foo.txt.tmp > foo.txt
rm -f foo.txt.tmp
Tất nhiên, trong trường hợp đó bạn cũng có thể sử dụng head -n -1
thay vì sed
.
Hệ điều hành Mac:
Trên Mac OS X (kể từ ngày 10.7.4), tương đương với sed -i
lệnh trên là
sed -i '' -e '$ d' foo.txt
$ d
một regex. Đó là một lệnh sed. d
là lệnh xóa một dòng, trong khi đó $
có nghĩa là "dòng cuối cùng trong tệp". Khi chỉ định một vị trí (được gọi là "phạm vi" trong sed lingo) trước một lệnh, lệnh đó chỉ được áp dụng cho vị trí đã chỉ định. Vì vậy, lệnh này nói rõ ràng "trong phạm vi của dòng cuối cùng trong một tệp, xóa nó". Khá lắt léo và đi thẳng vào vấn đề, nếu bạn hỏi tôi.
Đây là giải pháp nhanh nhất và đơn giản nhất, đặc biệt là trên các tệp lớn:
head -n -1 foo.txt > temp.txt ; mv temp.txt foo.txt
Nếu bạn muốn xóa dòng trên cùng, hãy sử dụng:
tail -n +2 foo.txt
có nghĩa là các dòng đầu ra bắt đầu từ dòng 2.
Không sử dụng sed
để xóa các dòng từ trên cùng hoặc dưới cùng của tệp - sẽ rất chậm nếu tệp lớn.
head -n -1 foo.txt
là đủ
brew install coreutils
(tiện ích lõi GNU) và sử dụng ghead
thay vì head
.
FILE=$1; TAIL=$2; head -n -${TAIL} ${FILE} > temp ; mv temp ${FILE}
Chạy nó để xóa 4 dòng ví dụ từ myfile như: ./TAILfixer myfile 4
tất nhiên trước tiên làm cho nó có thể thực thi được bằngchmod +x TAILfixer
sed
, lệnh này cũng khá chậm
Tôi gặp rắc rối với tất cả các câu trả lời ở đây vì tôi đang làm việc với tệp HUGE (~ 300Gb) và không có giải pháp nào được thu nhỏ. Đây là giải pháp của tôi:
dd if=/dev/null of=<filename> bs=1 seek=$(echo $(stat --format=%s <filename> ) - $( tail -n1 <filename> | wc -c) | bc )
Nói cách: Tìm ra độ dài của tệp bạn muốn kết thúc bằng (độ dài của tệp trừ đi độ dài của dòng cuối cùng của nó, bằng cách sử dụng bc
) và đặt vị trí đó là cuối của tệp (bằng cách nhập dd
một byte /dev/null
vào nó).
Việc này rất nhanh vì tail
bắt đầu đọc từ cuối và dd
sẽ ghi đè tệp vào vị trí thay vì sao chép (và phân tích) mọi dòng của tệp, đó là những gì các giải pháp khác làm.
LƯU Ý: Thao tác này sẽ xóa dòng khỏi tệp tại chỗ! Tạo một bản sao lưu hoặc kiểm tra trên một tập tin giả trước khi thử nó trên tập tin của riêng bạn!
Để xóa dòng cuối cùng khỏi tệp mà không cần đọc toàn bộ tệp hoặc viết lại bất cứ thứ gì , bạn có thể sử dụng
tail -n 1 "$file" | wc -c | xargs -I {} truncate "$file" -s -{}
Để xóa dòng cuối cùng và cũng in nó trên thiết bị xuất chuẩn ("pop" nó), bạn có thể kết hợp lệnh đó với tee
:
tail -n 1 "$file" | tee >(wc -c | xargs -I {} truncate "$file" -s -{})
Các lệnh này có thể xử lý một cách hiệu quả một tệp rất lớn. Điều này tương tự và được lấy cảm hứng từ câu trả lời của Yossi, nhưng nó tránh sử dụng một vài chức năng bổ sung.
Nếu bạn sẽ sử dụng chúng nhiều lần và muốn xử lý lỗi và một số tính năng khác, bạn có thể sử dụng poptail
lệnh tại đây:
https://github.com/donm/evenmoreutils
truncate
không có sẵn trên OS X theo mặc định. Nhưng thật dễ dàng để cài đặt bằng cách sử dụng bia : brew install truncate
.
Người dùng Mac
nếu bạn chỉ muốn dòng đầu ra bị xóa mà không thay đổi tập tin
sed -e '$ d' foo.txt
nếu bạn muốn xóa dòng cuối cùng của chính tệp đầu vào
sed -i '' -e '$ d' foo.txt
-i ''
cho sed sửa đổi tệp tại chỗ, trong khi giữ bản sao lưu trong tệp có phần mở rộng được cung cấp dưới dạng tham số. Vì tham số là một chuỗi rỗng, không có tệp sao lưu nào được tạo. -e
nói với sed để thực hiện một lệnh. Lệnh này $ d
có nghĩa là: tìm dòng cuối cùng ( $
) và xóa nó ( d
).
Trên máy Mac, đầu -n -1 sẽ không hoạt động. Và, tôi đã cố gắng tìm một giải pháp đơn giản [mà không phải lo lắng về thời gian xử lý] để giải quyết vấn đề này chỉ bằng cách sử dụng các lệnh "head" và / hoặc "tail".
Tôi đã thử chuỗi lệnh sau đây và rất vui vì tôi có thể giải quyết nó chỉ bằng cách sử dụng lệnh "tail" [với các tùy chọn có sẵn trên Mac]. Vì vậy, nếu bạn đang ở trên Mac và chỉ muốn sử dụng "đuôi" để giải quyết vấn đề này, bạn có thể sử dụng lệnh này:
tập tin mèo | đuôi -r | đuôi -n +2 | đuôi -r
1> tail -r: chỉ cần đảo ngược thứ tự các dòng trong đầu vào của nó
2> tail -n +2: điều này in tất cả các dòng bắt đầu từ dòng thứ hai trong đầu vào của nó
ghead -n -1
awk 'NR>1{print buf}{buf = $0}'
Về cơ bản, mã này cho biết như sau:
Đối với mỗi dòng sau đầu tiên, in dòng đệm
cho mỗi dòng, đặt lại bộ đệm
Bộ đệm bị trễ bởi một dòng, do đó bạn kết thúc việc in các dòng từ 1 đến n-1
awk "NR != `wc -l < text.file`" text.file |> text.file
Đoạn trích này thực hiện các mẹo.
Cả hai giải pháp này đều ở đây trong các hình thức khác. Tôi thấy những điều này thực tế hơn một chút, rõ ràng và hữu ích:
Sử dụng dd:
BADLINESCOUNT=1
ORIGINALFILE=/tmp/whatever
dd if=${ORIGINALFILE} of=${ORIGINALFILE}.tmp status=none bs=1 count=$(printf "$(stat --format=%s ${ORIGINALFILE}) - $(tail -n${BADLINESCOUNT} ${ORIGINALFILE} | wc -c)\n" | bc )
/bin/mv -f ${ORIGINALFILE}.tmp ${ORIGINALFILE}
Sử dụng cắt ngắn:
BADLINESCOUNT=1
ORIGINALFILE=/tmp/whatever
truncate -s $(printf "$(stat --format=%s ${ORIGINALFILE}) - $(tail -n${BADLINESCOUNT} ${ORIGINALFILE} | wc -c)\n" | bc ) ${ORIGINALFILE}
sed '$d' ~/path/to/your/file/name
sed -i '' -e '$ d' ~/path/to/your/file/name
Đây là cách bạn có thể thực hiện thủ công (Cá nhân tôi sử dụng phương pháp này rất nhiều khi tôi cần nhanh chóng xóa dòng cuối cùng trong một tệp):
vim + [FILE]
Cái đó +
dấu hiệu có nghĩa là khi các tập tin được mở ra trong trình soạn thảo văn bản vim, con trỏ sẽ được bố trí trên dòng cuối cùng của tập tin.
Bây giờ chỉ cần nhấn d
hai lần trên bàn phím của bạn. Điều này sẽ làm chính xác những gì bạn muốn loại bỏ dòng cuối cùng. Sau đó, nhấn :
theo sau x
và sau đó nhấn Enter
. Điều này sẽ lưu các thay đổi và đưa bạn trở lại vỏ. Bây giờ, dòng cuối cùng đã được gỡ bỏ thành công.
sed -i
lệnh trên làsed -i '' -e '$ d' foo.txt
. Ngoài ra,head -n -1
hiện tại sẽ không hoạt động trên máy Mac.