59

我一直试图让该head实用程序显示除最后一行标准输入之外的所有内容。我需要的实际代码类似于cat myfile.txt | head -n $(($(wc -l)-1)). 但这没有用。我在 Darwin/OS X 上这样做,它没有很好的语义head -n -1,会让我得到类似的输出。

这些变化都不起作用。

cat myfile.txt | head -n $(wc -l | sed -E -e 's/\s//g')
echo "hello" | head -n $(wc -l | sed -E -e 's/\s//g')

我测试了更多的变化,特别是发现这个工作:

cat <<EOF | echo $(($(wc -l)-1))
>Hola
>Raul
>Como Esta
>Bueno?
>EOF
3

这里有一些更简单的东西也有效。

echo "hello world" | echo $(($(wc -w)+10))

可以理解的是,这给了我一个非法的行数错误。但它至少告诉我,head程序在将内容传递给子外壳/命令替换之前没有使用标准输入,这是一种遥远的可能性,但无论如何我都想排除这种可能性。

echo "hello" | head -n $(cat && echo 1)

是什么解释了这里的子shell 的行为head及其wc相互作用?谢谢你的帮助。

4

6 回答 6

90

head -n -1将为您提供除输入的最后一行之外的所有内容。

于 2013-08-08T13:47:43.177 回答
75

head是错误的工具。如果您想查看除最后一行之外的所有内容,请使用:

sed \$d

原因是

# Sample of incorrect code:
echo "hello" | head -n $(wc -l | sed -E -e 's/\s//g')

失败是wc消耗所有输入并且没有什么head可看的。 wc从运行它的子 shell 继承它的标准输入,它从echo. 一旦它消耗了输入,它就会返回,然后head尝试读取数据……但一切都消失了。如果您想读取两次输入,则必须将数据保存在某处。

于 2013-08-08T13:49:28.080 回答
13

使用 sed:

sed '$d' filename

将删除文件的最后一行。

$ seq 1 10 | sed '$d' 
1
2
3
4
5
6
7
8
9
于 2013-08-08T13:56:35.797 回答
10

特别是对于 Mac OS X,我在此 Q&A 的评论中找到了答案。

假设您使用的是 Homebrew,运行brew install coreutils然后使用ghead命令:

cat myfile.txt | ghead -n -1

或者,等效地:

ghead -n -1 myfile.txt

最后,看看brew info coreutils您是否想使用不带g前缀的命令(例如,head代替ghead)。

于 2016-06-13T13:52:46.837 回答
6
cat myfile.txt | echo $(($(wc -l)-1))

这行得通。它过于复杂:你可以只写echo $(($(wc -l)-1)) <myfile.txtor echo $(($(wc -l <myfile.txt)-1))。问题是你使用它的方式。

cat myfile.txt | head -n $(wc -l | sed -E -e 's/\s//g')

wc在计算行数时消耗所有输入。因此,在启动时,管道中没有数据可供读取head

如果您的输入来自一个文件,您可以同时wchead该文件重定向。

head -n $(($(wc -l <myfile.txt) - 1)) <myfile.txt

如果您的数据可能来自管道,则需要复制它。复制流的常用工具是tee,但这还不够,因为来自的两个输出tee是以相同的速率产生的,而这里wc需要在开始之前完全消耗它的输出head。因此,您需要使用一个可以检测最后一行的工具,这无论如何都是一种更有效的方法。

方便的是,sed 提供了一种匹配最后一行的方法。打印除最后一行以外的所有行,或抑制最后一行输出,都可以:

sed -n '$! p'
sed '$ d'
于 2013-08-08T14:15:22.997 回答
0
awk 'NR>1{print p}{p=$0}'

对于这项工作,awk one-liner 比 sed 长一点。

于 2013-08-08T13:56:42.120 回答