Bash 让head显示除最后一行以外的所有文件:命令替换和标准I/O重定向

Bash 让head显示除最后一行以外的所有文件:命令替换和标准I/O重定向,bash,unix,pipe,Bash,Unix,Pipe,我一直试图让head实用程序显示标准输入的最后一行以外的所有内容。我需要的实际代码大致是catmyfile.txt | head-n$($(wc-l)-1))。但那没用。我是在Darwin/OSX上做这件事的,它没有很好的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//

我一直试图让
head
实用程序显示标准输入的最后一行以外的所有内容。我需要的实际代码大致是
catmyfile.txt | head-n$($(wc-l)-1))
。但那没用。我是在Darwin/OSX上做这件事的,它没有很好的
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
这一次给了我一个非法的行计数错误,这是可以理解的。但它至少告诉我,
head
程序在将内容传递到subshell/命令替换之前没有使用标准输入,这是一种遥远的可能性,但无论如何我都想排除这种可能性

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

如何解释
head
wc
的行为及其通过子shell的交互作用?感谢您的帮助。

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

head
是错误的工具。如果要查看除最后一行以外的所有行,请使用:

sed \$d
原因是

# Sample of incorrect code:
echo "hello" | head -n $(wc -l | sed -E -e 's/\s//g')
失败的原因是
wc
消耗了所有输入,并且没有任何内容可供
head
查看
wc
从运行它的子shell继承其stdin,该子shell从
echo
的输出读取数据。一旦它使用了输入,它就会返回,然后
head
尝试读取数据……但数据都消失了。如果要读取两次输入,则必须将数据保存在某个位置。

使用sed:

sed '$d' filename
将删除文件的最后一行

$ seq 1 10 | sed '$d' 
1
2
3
4
5
6
7
8
9
对于这项工作,awk一行程序比sed一行程序长一点

cat myfile.txt | echo $(($(wc -l)-1))

这很有效。这太复杂了:你可以只为MacOSX写
echo$($(wc-l)-1)),具体来说,我从一个

假设您使用的是自制软件,请运行
brew install coreutils
,然后使用
ghead
命令:

cat myfile.txt | ghead -n -1
或者,相当于:

ghead -n -1 myfile.txt

最后,如果要使用不带
g
前缀的命令(例如,
head
而不是
ghead
),请参阅
brew info coreutils

如果您碰巧使用了支持该语法的
head
。不是所有人都这样。谢谢@dunc123。但是我补充了一个说明,我不支持
head-n-1
。谢谢@William。我可以使用
sed
,但在这个问题上,我特别想了解为什么使用
head
的方法不起作用。+1究竟为什么会被否决?sed
sed
脚本绝对是正确的、可移植的解决方案,我发现解释中没有任何缺陷。否决票是合理的。当答案是根本没有解决问题的
sed
解决方案时,就会出现这种情况。@aerijman
\$d
是另一种书写
'$d'
的方式。
$
处理最后一行,命令
d
应用于该行。也就是说,它会删除最后一行。@aerijman
sed
不太擅长寻址文件末尾的行。使用gnu head(来自coreutils 8.30),您可以执行
head-n-$n
(例如,
head-n-5
以查看除最后5行以外的所有行)。与所示的
head
解决方案不同,此
sed
方法适用于FreeBSD。
cat myfile.txt | head -n $(wc -l | sed -E -e 's/\s//g')
head -n $(($(wc -l <myfile.txt) - 1)) <myfile.txt
sed -n '$! p'
sed '$ d'
cat myfile.txt | ghead -n -1
ghead -n -1 myfile.txt