簡體   English   中英

從 Bash 中的文件中刪除最后一行

[英]Remove the last line from a file in Bash

我有一個文件foo.txt ,其中包含以下幾行:

a
b
c

我想要一個簡單的命令,導致foo.txt的內容是:

a
b

使用GNU sed

sed -i '$ d' foo.txt

-i選項在 3.95 之前的GNU sed版本中不存在,因此您必須將其用作帶有臨時文件的過濾器:

cp foo.txt foo.txt.tmp
sed '$ d' foo.txt.tmp > foo.txt
rm -f foo.txt.tmp

當然,在這種情況下,您也可以使用head -n -1而不是sed

操作系統:

在 Mac OS X(從 10.7.4 開始)上,相當於上面的sed -i命令是

sed -i '' -e '$ d' foo.txt

這是迄今為止最快和最簡單的解決方案,尤其是在大文件上:

head -n -1 foo.txt > temp.txt ; mv temp.txt foo.txt

如果要刪除頂行,請使用以下命令:

tail -n +2 foo.txt

這意味着從第 2 行開始的輸出行。

不要使用sed從文件的頂部或底部刪除行——如果文件很大,它會非常慢。

對於大文件

我在這里的所有答案都遇到了麻煩,因為我正在處理一個巨大的文件(~300Gb)並且沒有一個解決方案可以擴展。 這是我的解決方案:

filename="example.txt"

file_size="$(stat --format=%s "$filename")"
trim_count="$(tail -n1 "$filename" | wc -c)"
end_position="$(echo "$file_size - $trim_count" | bc)"

dd if=/dev/null of="$filename" bs=1 seek="$end_position"

或者,作為單襯:

dd if=/dev/null of=<filename> bs=1 seek=$(echo $(stat --format=%s <filename> ) - $( tail -n1 <filename> | wc -c) | bc )

用字詞:找出您想要結束的文件的長度(文件的長度減去其最后一行的長度,使用bc ),並將該位置設置為文件的末尾(通過dd ing 一個字節/dev/null到它)。

這很快,因為tail從末尾開始讀取,而dd將覆蓋文件原地,而不是復制(和解析)文件的每一行,這是其他解決方案所做的。

注意:這會從文件中刪除該行! 在您自己的文件上嘗試之前,請先備份或測試一個虛擬文件!

要從文件中刪除最后一行而不讀取整個文件或重寫任何內容,您可以使用

tail -n 1 "$file" | wc -c | xargs -I {} truncate "$file" -s -{}

要刪除最后一行並將其打印在標准輸出上(“彈出”它),您可以將該命令與tee結合使用:

tail -n 1 "$file" | tee >(wc -c | xargs -I {} truncate "$file" -s -{})

這些命令可以有效地處理非常大的文件。 這類似於 Yossi 的回答並受到其啟發,但它避免了使用一些額外的功能。

如果您要重復使用這些並想要錯誤處理和一些其他功能,您可以在此處使用poptail命令: https : //github.com/donm/evenmoreutils

對於 Mac 用戶:

在 Mac 上, head -n -1 不起作用。 而且,我試圖找到一個簡單的解決方案 [無需擔心處理時間] 僅使用“head”和/或“tail”命令來解決這個問題。

我嘗試了以下命令序列,很高興我可以只使用“tail”命令 [ 使用 Mac 上可用的選項 ] 來解決它。 所以,如果你在 Mac 上,並且只想使用“tail”來解決這個問題,你可以使用這個命令:

貓文件.txt | 尾巴 -r | 尾 -n +2 | 尾-r

說明:

1> tail -r :簡單地顛倒其輸入中的行順序

2> tail -n +2 :這將打印從其輸入中的第二行開始的所有行

Mac 用戶

如果您只想刪除最后一行的輸出而不更改文件本身

sed -e '$ d' foo.txt

如果要刪除輸入文件本身的最后一行,請執行

sed -i '' -e '$ d' foo.txt

echo -e '$d\nw\nq'| ed foo.txt
awk 'NR>1{print buf}{buf = $0}'

本質上,這段代碼說明如下:

對於第一行之后的每一行,打印緩沖行

對於每一行,重置緩沖區

緩沖區滯后一行,因此您最終會打印第 1 到 n-1 行

Linux

$ 是最后一行,d 是刪除:

sed '$d' ~/path/to/your/file/name

操作系統

相當於 sed -i

sed -i '' -e '$ d' ~/path/to/your/file/name

這是使用海綿的解決方案(來自moreutils包):

head -n -1 foo.txt | sponge foo.txt

解決方案總結:

  1. 如果您想快速解決大文件,請使用高效的 taildd方法。

  2. 如果您想要一些易於擴展/調整和便攜的東西,請使用重定向和移動方法。

  3. 如果你想要一些易於擴展/調整的東西,文件不是太大,便攜性(即,取決於moreutils包)不是問題,而且你是方褲的粉絲,可以考慮海綿方法。

與“重定向和移動”方法相比,海綿方法的一個很好的好處是海綿保留了文件權限。

與“重定向和移動”方法相比,Sponge 使用了更多的 RAM。 這會提高一點速度(只有大約 20%),但是如果您對速度感興趣,那么“高效尾部”和 dd 方法是要走的路。

awk "NR != `wc -l < text.file`" text.file &> newtext.file

這個片段可以解決問題。

這兩種解決方案都以其他形式存在。 我發現這些更實用、更清晰、更有用:

使用 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}

使用截斷:

BADLINESCOUNT=1
ORIGINALFILE=/tmp/whatever
truncate -s $(printf "$(stat --format=%s ${ORIGINALFILE}) - $(tail -n${BADLINESCOUNT} ${ORIGINALFILE} | wc -c)\n" | bc ) ${ORIGINALFILE}

以下是您可以手動執行的方法(當我需要快速刪除文件中的最后一行時,我個人經常使用此方法):

vim + [FILE]

那里的+號表示在 vim 文本編輯器中打開文件時,光標將定位在文件的最后一行。

現在只需在鍵盤上按d兩次即可。 這將完全符合您的要求——刪除最后一行。 之后,按:然后按x然后按Enter 這將保存更改並使您返回到 shell。 現在,最后一行已成功刪除。

您也可以嘗試此方法:刪除最后 n 行的示例。

a=0; while [ $a -lt 4 ]; do sed -i '$ d' output.txt; a= expr $a + 1 ;完成

從文件(output.txt)中刪除最后 4 行。

可以處理大量數據並且輸出還可以,但是有一條垃圾線。

如果我將腳本的輸出通過管道傳輸到:

| sed -i '$ d' 我會得到以下錯誤,最后根本沒有輸出 sed: no input files

但是| head -n -1 有效!

紅寶石(1.9+)

ruby -ne 'BEGIN{prv=""};print prv ; prv=$_;' file

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM