【问题标题】:How to use sed to remove the last n lines of a file如何使用 sed 删除文件的最后 n 行
【发布时间】:2012-11-03 01:18:24
【问题描述】:

我想从文件末尾删除一些 n 行。这可以使用 sed 完成吗?

例如,要删除从 2 到 4 的行,我可以使用

$ sed '2,4d' file

但我不知道行号。我可以使用

删除最后一行
$sed $d file

但我想知道从末尾删除 n 行的方法。请让我知道如何使用 sed 或其他方法来做到这一点。

【问题讨论】:

  • @arashkordi:使用文件顶部的行数,而不是底部。
  • superusers上的相关问题。
  • // ,也许考虑改写问题以使其比just sed更笼统?
  • sed $d file 返回错误。相反,$d 应该在引号内,如下所示:sed '$d' file

标签: linux bash shell sed


【解决方案1】:

我不知道sed,但可以使用head

head -n -2 myfile.txt

【讨论】:

  • +1 为简单起见。等效的 sed 命令很丑:sed -e :a -e '$d;N;2,5ba' -e 'P;D' file(最后 5 行为,5)。
  • 请注意,这适用于 head 的某些版本,但不是标准的。事实上,head 的标准规定:The application shall ensure that the number option-argument is a positive decimal integer.
  • 添加到@WilliamPursell 的答案...在 Mac OS 默认外壳上,这不起作用。
  • 在 BSD 上也不是,但问题被标记为 Linux。
  • 减 1,因为除了 osx,这在 Ubuntu14 上对我不起作用 - head: illegal line count -- -2
【解决方案2】:

如果硬编码 n 是一个选项,您可以使用顺序调用 sed。例如,要删除最后三行,请将最后一行删除三次:

sed '$d' file | sed '$d' | sed '$d'

【讨论】:

  • 这个,加上 -i 来编辑文件而不是将其转储到标准输出,对我有用。
  • 不知道为什么 |管道不工作,;为我工作。
【解决方案3】:

来自sed one-liners

# delete the last 10 lines of a file
sed -e :a -e '$d;N;2,10ba' -e 'P;D'   # method 1
sed -n -e :a -e '1,10!{P;N;D;};N;ba'  # method 2

似乎正是你想要的。

【讨论】:

  • @Thor 您可以通过更改'$d;N;2,10ba' 中的10 来更改从文件中删除的行数
  • @AlexejMagura:我在评论答案的早期版本。
  • 对不起,我对 sed 命令还很陌生,这让我很困惑。如何使用此命令指定要应用的文件?
【解决方案4】:

一个有趣而简单的sedtac 解决方案:

n=4
tac file.txt | sed "1,$n{d}" | tac

注意

  • shell 需要双引号 " 来评估 sed 命令中的 $n 变量。在单引号中,不会执行插值。
  • tac 是一个 cat 反转,请参阅 man 1 tac
  • sed 中的{} 用于分隔$nd(如果不是,shell 会尝试插入不存在的$nd 变量)

【讨论】:

  • @MichaelDurrant port info coreutils || brew info coreutils;
【解决方案5】:

使用sed,但让shell 计算,目标是通过给出一个范围(删除最后23 行)来使用d 命令:

sed -i "$(($(wc -l < file)-22)),\$d" file

从内到外删除最后 3 行:

$(wc -l < file)

给出文件的行数:比如 2196

我们要删除最后 23 行,所以对于左侧或范围:

$((2196-22))

给:2174 因此shell解释后的原始sed是:

sed -i '2174,$d' file

-i 进行就地编辑,文件现在是 2173 行!

如果要将其保存到新文件中,代码为:

sed -i '2174,$d' file > outputfile

【讨论】:

    【解决方案6】:

    您可以为此使用 head

    使用

    $ head --lines=-N file &gt; new_file

    其中 N 是要从文件中删除的行数。

    原始文件的内容减去最后 N 行现在在 new_file

    【讨论】:

      【解决方案7】:

      为了完整起见,我想添加我的解决方案。 我最终用标准的ed 做到了这一点:

      ed -s sometextfile <<< $'-2,$d\nwq'
      

      这会使用就地编辑删除最后 2 行(尽管它确实使用了 /tmp 中的临时文件!!)

      【讨论】:

        【解决方案8】:

        要真正就地截断非常大的文件,我们有truncate 命令。 它不知道行,但是tail + wc 可以将行转换为字节:

        file=bigone.log
        lines=3
        truncate -s -$(tail -$lines $file | wc -c) $file
        

        如果同时写入文件,则存在明显的竞争条件。 在这种情况下,使用head 可能会更好——它从文件的开头开始计算字节数(mind disk IO),所以我们总是会在行边界上截断(如果文件被主动写入,可能会比预期的行更多):

        truncate -s $(head -n -$lines $file | wc -c) $file
        

        如果您尝试使用密码代替用户名登录失败,那么方便的单行:

        truncate -s $(head -n -5 /var/log/secure | wc -c) /var/log/secure
        

        【讨论】:

          【解决方案9】:

          这可能对你有用(GNU sed):

          sed ':a;$!N;1,4ba;P;$d;D' file
          

          【讨论】:

          • 不错。您错过了结尾的撇号 (')。
          • 抱歉这么晚发表评论,但我尝试(适用于我的 AIX/posix)它未能打印除最后一行之外的所有内容。阅读代码,我不明白最后四行是如何被删除的,显式循环位于前 4 行,所以它肯定会在 dDP 之后循环使用 GNU sed 而不是 posix 版本.似乎在D 之后没有打印行并保留在工作缓冲区中以进行新循环,而不会传递到操作行的“结束”。
          • @NeronLeVelu 程序将 4 行的窗口读取到模式空间中,然后附加下一行并打印第一行,直到到达文件末尾并删除其余行。
          • @potong 是的,我在 GNU sed 上进行了测试,它在 posix 卸载它的行之间保留了缓冲区,D 产生了相反的效果。
          【解决方案10】:

          以上大部分答案似乎都需要 GNU 命令/扩展:

              $ head -n -2 myfile.txt
              -2: Badly formed number
          

          对于更便携的解决方案:

               perl -ne 'push(@fifo,$_);print shift(@fifo) if @fifo > 10;'
          

               perl -ne 'push(@buf,$_);END{print @buf[0 ... $#buf-10]}'
          

               awk '{buf[NR-1]=$0;}END{ for ( i=0; i < (NR-10); i++){ print buf[i];} }'
          

          其中“10”是“n”。

          【讨论】:

            【解决方案11】:

            有了这里的答案,您已经知道 sed 不是这个应用程序的最佳工具。

            但是我确实认为使用 sed 可以做到这一点;这个想法是附加 N 行以保留空间,直到您能够阅读而不会碰到 EOF。当遇到 EOF 时,打印保持空间的内容并退出。

            sed -e '$!{N;N;N;N;N;N;H;}' -e x
            

            上面的 sed 命令将省略最后 5 行。

            【讨论】:

              【解决方案12】:

              分三步完成:

              a) 计算要编辑的文件的行数:

               n=`cat myfile |wc -l`
              

              b) 从该数字中减去要删除的行数:

               x=$((n-3))
              

              c) 告诉 sed 从该行号 ($x) 删除到末尾:

               sed "$x,\$d" myfile
              

              【讨论】:

              • 数学不好。如果您必须删除 3 行,则减去 3 但添加 1。根据您的数学计算,如果文件有 10 行,则 10 - 3 = 7 并且您使用 sed 删除第 7 到 10 行,即 4 行,而不是3.
              【解决方案13】:

              您可以使用wc -l &lt;file&gt; 获取总行数并使用

              head -n &lt;total lines - lines to remove&gt; &lt;file&gt;

              【讨论】:

                【解决方案14】:

                试试下面的命令:

                n = line number
                tail -r file_name | sed '1,nd' | tail -r
                

                【讨论】:

                • 请解释这是如何工作的。仅供参考 - 要初始化 shell 变量,= 周围不应有空格。
                • @codeforester 第一行是我猜的评论。他只是使用tail -r 而其他人使用tac 来反转行顺序,并使最后的n 行成为n 的第一行。
                【解决方案15】:

                这将删除 file 的最后 3 行:

                for i in $(seq 1 3); do sed -i '$d' file; done;

                【讨论】:

                • 这对于大文件来说太昂贵了——整个文件必须被读取和重写 n 次!和sed 一样多的叉子。
                • 虽然这可能不是最有效的解决方案,但它是最直接和容易理解的
                【解决方案16】:

                我更喜欢这个解决方案;

                head -$(gcalctool -s $(cat file | wc -l)-N) file
                

                其中 N 是要删除的行数。

                【讨论】:

                  【解决方案17】:
                  sed -n ':pre
                  1,4 {N;b pre
                      }
                  :cycle
                  $!{P;N;D;b cycle
                    }' YourFile
                  

                  posix版本

                  【讨论】:

                    【解决方案18】:

                    删除最后 4 行:

                    $ nl -b a file | sort -k1,1nr | sed '1, 4 d' | sort -k1,1n | sed 's/^ *[0-9]*\t//'   
                    

                    【讨论】:

                    • 与头部相比有点沉重(尤其是在资源方面)。至少tac file | sed '1,4d' | tac,因为排序然后删除前缀会消耗大量资源。
                    • @NeronLeVelu 你是对的但是没有tac 命令是一些系统(例如FreeBSD?)
                    【解决方案19】:

                    我想出了这个,其中 n 是您要删除的行数:

                    count=`wc -l file`
                    lines=`expr "$count" - n`
                    head -n "$lines" file > temp.txt
                    mv temp.txt file
                    rm -f temp.txt
                    

                    这是一个小环岛,但我认为它很容易遵循。

                    1. 统计主文件的行数
                    2. 从计数中减去要删除的行数
                    3. 打印出要保留并存储在临时文件中的行数
                    4. 用临时文件替换主文件
                    5. 删除临时文件

                    【讨论】:

                      【解决方案20】:

                      对于删除文件的最后N行,可以使用相同的概念

                      $ sed '2,4d' file
                      

                      您可以使用组合尾命令来反转文件:如果 N 为 5

                      $ tail -r file | sed '1,5d' file | tail -r > file
                      

                      这种方式也可以在 head -n -5 file 命令不运行的地方运行(就像在 mac 上一样!)。

                      【讨论】:

                        【解决方案21】:

                        在 docker 中,这对我有用:

                        head --lines=-N file_path >> file_path
                        

                        【讨论】:

                          【解决方案22】:
                          #!/bin/sh
                          
                          echo 'Enter the file name : '
                          read filename
                          
                          echo 'Enter the number of lines from the end that needs to be deleted :'
                          read n
                          
                          #Subtracting from the line number to get the nth line
                          m=`expr $n - 1`
                          
                          # Calculate length of the file
                          len=`cat $filename|wc -l`
                          
                          #Calculate the lines that must remain
                          lennew=`expr $len - $m`
                          
                          sed "$lennew,$ d" $filename
                          

                          【讨论】:

                          • 从系统中读取任意文件并选择任意长度
                          【解决方案23】:

                          这将删除最后 12 行

                          sed -n -e :a -e '1,10!{P;N;D;};N;ba'
                          

                          【讨论】:

                          • 请稍作解释。
                          猜你喜欢
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2018-07-20
                          • 1970-01-01
                          • 2021-12-06
                          • 1970-01-01
                          • 2017-07-16
                          相关资源
                          最近更新 更多