文件中的行数未知。如何在Unix平台上用一行命令(必要时可以使用多行)删除第n行(从下往上算)。
答案1
例如,要使用以下命令删除底部的第四行sed
:
tac input | sed '4d' | tac
要覆盖输入文件:
tmpfile=$(mktemp)
tac input | sed '4d' | tac > "$tmpfile" && mv "$tmpfile" input
答案2
纯的sed
:
如果n是 1:
sed '$ d'
这很简单:如果是最后一行,则删除模式空间,这样就不会打印它。
如果n大于 1(可用作
$n
):sed " : start 1,$((n-1)) { N; b start } $ { t end; s/^//; D } N P D : end "
注意在启动
$((n-1))
之前由 shell 展开sed
。这个片段
: start 1,$((n-1)) { N; b start }
商店n模式空间中的 -1 行。如果
sed
在此循环中到达输入流的末尾,则将自动打印模式空间(从末尾开始没有第 n 行,不会删除任何行)。假设有更多的输入。然后,在到达最后一行之前,迭代此片段:
N # read the next line of input and append it to the pattern space P # print the first line from the pattern space D # delete the first line from the pattern space and start a new cycle
这样,模式空间就是我们的缓冲区,它使输出根据输入“延迟”几行。
N
从这个片段中也可以读取输入的最后一行。读取最后一行后,将执行:
$ { t end; s/^//; D }
当第一次执行此代码时,
t
不会分支到,end
因为之前没有成功替换。s/^//
然后执行这种无操作替换,并且模式空间中的第一行被删除 (D
) 而不被打印。这正是您要删除的行。由于D
开始了新的循环,同一行代码最终会再次被执行。这次t
将分支到end
.当
sed
到达脚本末尾时,将自动打印模式空间。这样所有剩余的行都会被打印出来。该命令将为
n=2
(有效)和n=1
(无效)生成相同的输出。我试图找到一个无论什么情况都有效的单一解决方案n。我失败了,因此当你的特殊情况n是 1。
答案3
如果$n
保留要删除的行数
删除单行使用
printf "\$-%d+1,\$-%d+1d\nwq\n" $n $n| ed -s file
删除最后 n 行
printf "\$-%d,\$d\nwq\n" $n | ed -s file
在哪里
\$%d,\$d
告诉 ed 删除最后 n 行(printf 将插入 n)wq
写完然后退出-s
ined -s
会让ed保持沉默。请注意,没有规定检查是否有足够的行可以删除。
可悲的是范围从结束不能在sed
...中指定
答案4
您可以结合head
和tail
来实现这一点。
如果第n个需要删除底部的一行
head
从标准输入读取并向标准输出报告总-n从顶部开始的线条tail
读取并报告到底部的标准输出n-1来自标准输入的行。- 作为一个整体,这些行将按顺序报告到标准输出,并跳过从末尾开始的 *nth` 行
此解决方案取决于head
将打开文件描述的文件偏移量保留在最后报告的行之后 - 我相信head
当标准输入从文件重定向时 GNU 确实会这样做
n=200; tmpfile=$(mktemp) && { head -n -$n; tail -n -$((n-1)); }<file >"$tmpfile" \
&& mv -- "$tmpfile" file