web-dev-qa-db-ja.com

`tail`と` head`の逆の動作を取得するにはどうすればよいですか?

ドキュメントをhead/tailして逆の出力を取得する方法はありますか。文書の行数がわからないからですか?

つまり別のドキュメントに追加するfoo.txtの最初の2行以外はすべて取得したいだけです。

57
chrisjlee

これを使用してfirstの2行を削除できます。

tail -n +3 foo.txt

そして、これはlast 2行を削除します。

head -n -2 foo.txt

(ファイルが後者の場合は\nで終わると仮定)


tailおよびheadの標準的な使用法と同様に、これらの操作は破壊的ではありません。出力を新しいファイルにリダイレクトする場合は、>out.txtを使用します。

tail -n +3 foo.txt >out.txt

out.txtがすでに存在する場合は、このファイルを上書きします。出力を>>out.txtに追加する場合は、>out.txtではなくout.txtを使用します。

59

最初のN-1行以外のすべてが必要な場合は、tailを行数+Nで呼び出します。 (番号は、保持したい最初の行の番号で、1から始まります。つまり、+ 1は先頭から開始することを意味し、+ 2は1行をスキップすることを意味します)。

tail -n +3 foo.txt >>other-document

最後のN行をスキップする簡単で移植可能な方法はありません。 GNU headhead -n +Nの対応としてtail -n +Nを許可します。それ以外の場合、tacがあれば(例GNUまたはBusybox)、それをテールと組み合わせることができます:

tac | tail -n +3 | tac

移植性の高い、awkフィルターを使用できます(テストされていません)。

awk -vskip=2 '{
    lines[NR] = $0;
    if (NR > skip) print lines[NR-skip];
    delete lines[NR-skip];
}'

大きなファイルから最後の数行を削除する場合は、切り捨てるピースのバイトオフセットを決定してから、ddで切り捨てを実行できます。

total=$(wc -c < /file/to/truncate)
chop=$(tail -n 42 /file/to/truncate | wc -c)
dd if=/dev/null of=/file/to/truncate seek=1 bs="$((total-chop))"

最初にファイルを切り捨てることはできませんが、巨大なファイルの最初の数行を削除する必要がある場合は、 内容を移動 できます。

tail manページから(GNU tail、つまり):

-n, --lines=K
   output the last K lines, instead of the last 10; or use -n +K to
   output lines starting with the Kth

したがって、以下はsomefile.txtの最初の2行を除くすべてをanotherfile.txtに追加する必要があります。

tail --lines=+3 somefile.txt >> anotherfile.txt
3
Steven Monday

最初のn行を削除するにはGNU= sedを使用できます。たとえば、n = 2の場合

sed -n '1,2!p' input-file

!「この間隔を除外する」という意味です。ご想像のとおり、たとえば、より複雑な結果を得ることができます

sed -n '3,5p;7p'

3、4、5、7行目が表示されます。アドレスの代わりに正規表現を使用すると、より強力になります。

制限は、行番号が事前にわかっている必要があることです。

3
enzotib
_{   head -n2 >/dev/null
    cat  >> other_document
}   <infile
_

_<infile_が通常のlseek()-ableファイルである場合、はい、ぜひともお気軽に。上記は完全にPOSIXでサポートされている構造です。

2
mikeserv

tail -n +4 4行目(最初の3行を除くすべて)からファイルを出力することは標準的で移植性があり、そのheadに相当するもの(head -n -3、最後の3行を除くすべて)はそうではありません。

移植性の高い、あなたはそうするでしょう:

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

または:

sed -ne :1 -e '1,3{N;b1' -e '}' -e 'P;N;D'

sedに制限されたサイズのパターンスペースがある一部のシステムでは、nの大きな値にスケーリングされないことに注意してください)。

または:

awk 'NR>3 {print l[NR%3]}; {l[NR%3]=$0}'
1

diffを使用してhead/tailの出力を元のファイルと比較し、同じものを削除して、逆を取得できます。

diff --unchanged-group-format='' foo.txt <(head -2 foo.txt)
1
sokoban

私のアプローチはGillesに似ていますが、代わりにcatでファイルを反転し、headコマンドでパイプします。

tac -r thefile.txt | head thisfile.txt(ファイルを置き換えます)

0
Abe

BSD(macOS)のソリューション:

最初の2行を削除:

tail -n $( echo "$(cat foo.txt | wc -l)-2" | bc )

最後の2行を削除:

head -n $( echo "$(cat foo.txt | wc -l)-2" | bc )

...あまりエレガントではありませんが、仕事は完了です!

0
spectrum

私があなたの必要性を明確に理解してくれれば幸いです。

リクエストを完了するには、いくつかの方法があります。

tail -n$(expr $(cat /etc/passwd|wc -l) - 2) /etc/passwd

ここで、/ etc/passwdはファイルです

巨大なファイルがある場合、2番目の解決策が役立つことがあります。

my1stline=$(head -n1 /etc/passwd)
my2ndline=$(head -n2 /etc/passwd|grep -v "$my1stline")
cat /etc/passwd |grep -Ev "$my1stline|$my2ndline"
0
Mathieu Coavoux