首页 文章

从Bash中的文件中删除最后一行

提问于
浏览
250

我有一个文件, foo.txt ,包含以下行:

a
b
c

我想要一个简单的命令,导致 foo.txt 的内容为:

a
b

11 回答

  • 12

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

    MacOS:

    在Mac OS X上(从10.7.4开始),相当于上面的 sed -i 命令

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

    这是迄今为止最快,最简单的解决方案,尤其是在大文件上:

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

    如果你想删除顶行使用这个:

    tail -n +2 foo.txt
    

    这意味着输出线从第2行开始 .

    不要使用 sed 删除文件顶部或底部的行 - 如果文件很大,则速度非常慢 .

  • 26

    我在这里得到了所有答案的麻烦,因为我正在使用一个巨大的文件(~300Gb)并且没有任何解决方案缩放 . 这是我的解决方案:

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

    单词:找出你想要最终得到的文件的长度(文件长度减去最后一行长度的长度,使用 bc ),并将该位置设置为文件的结尾(通过 dd 一个字节) /dev/null 到它上面) .

    这很快,因为 tail 从头开始读取, dd 将覆盖文件 in place 而不是复制(和解析)文件的每一行,这是其他解决方案所做的 .

    NOTE: This removes the line from the file in place! Make a backup or test on a dummy file before trying it out on your own file!

  • 227

    要从文件 without reading the whole file or rewriting anything 中删除最后一行,您可以使用

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

    要删除最后一行并将其打印在stdout("pop"它)上,您可以将该命令与 tee 组合:

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

    这些命令可以有效地处理非常大的文件 . 这与Yossi的回答类似,并受其启发,但它避免使用一些额外的功能 .

    如果您要反复使用这些并想要错误处理和其他一些功能,可以在此处使用 poptail 命令:https://github.com/donm/evenmoreutils

  • 99

    Mac用户

    如果你只想删除最后一行输出而不改变文件本身呢

    sed -e '$ d' foo.txt

    如果你想删除输入文件本身的最后一行呢

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

  • 16

    对于Mac用户:

    在Mac上,头-n -1不会工作 . 而且,我试图找到一个简单的解决方案[不用担心处理时间],只使用“head”和/或“tail”命令来解决这个问题 .

    我尝试了以下命令序列,并且很高兴我可以使用“tail”命令[使用Mac上的选项]来解决它 . 因此,如果您使用的是Mac,并且只想使用“tail”来解决此问题,则可以使用以下命令:

    cat file.txt | tail -r |尾巴-n 2 |尾巴-r

    说明:

    1> tail -r:简单地反转输入中的行顺序

    2> tail -n 2:打印输入中从第二行开始的所有行

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

    基本上,此代码说明如下:

    对于第一行之后的每一行,打印缓冲行

    对于每一行,重置缓冲区

    缓冲区滞后一行,因此最终会打印第1行到第n-1行

  • 8
    awk "NR != `wc -l < text.file`" text.file |> text.file
    

    这个片段可以解决这个问题 .

  • 46

    这两种解决方案都以其他形式出现 . 我发现这些更实用,清晰,有用:

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

    红宝石(1.9)

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

相关问题