web-dev-qa-db-ja.com

ファイルの最終行以外のすべてを表示するように頭を取得する:コマンド置換と標準I / Oリダイレクト

headユーティリティを取得して、標準入力の最後の行を除くすべてを表示しようとしています。実際に必要なコードは、cat myfile.txt | head -n $(($(wc -l)-1))の行に沿ったものです。しかし、それはうまくいきませんでした。私はこれをhead -n -1のニースセマンティクスを持たないDarwin/OS Xで行っています。

これらのバリエーションはいずれも機能しません。

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)

ここでheadwcの動作とサブシェルを介したそれらの相互作用を説明していますか?ご協力いただきありがとうございます。

38
gkb0986

headは間違ったツールです。最後の行以外をすべて表示する場合は、次を使用します。

sed \$d

その理由

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

失敗するのは、wcがすべての入力を消費し、headが表示するものが何もないことです。 wcは、実行しているサブシェルから標準入力を継承します。サブシェルは、echoの出力から読み取ります。入力を消費すると、戻り、headがデータの読み取りを試みますが、すべて消えてしまいます。入力を2回読み取る場合は、データをどこかに保存する必要があります。

47
William Pursell

head -n -1は、入力の最終行を除くすべてを提供します。

65
dunc123

Sedの使用:

sed '$d' filename

ファイルの最後の行を削除します。

$ seq 1 10 | sed '$d' 
1
2
3
4
5
6
7
8
9
11
devnull

特に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)。

6
Jimothy
_cat myfile.txt | echo $(($(wc -l)-1))
_

これは動作します。それは非常に複雑です:echo $(($(wc -l)-1)) <myfile.txtまたは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からの2つの出力は同じレートで生成されるため、ここでは十分ではありませんが、ここではwcは完全に消費する必要がありますheadを開始する前の出力。したがって、代わりに、最後の行を検出できる単一のツールを使用する必要があります。これは、いずれにしても効率的なアプローチです。

便利なことに、sedは最後の行を一致させる方法を提供します。最後の行を除くすべての行を印刷するか、最後の出力行を抑制します:

_sed -n '$! p'
sed '$ d'
_
4
Gilles
awk 'NR>1{print p}{p=$0}'

このジョブでは、awkワンライナーはsedワンライナーよりも少し長くなります。

0
Kent