ファイル内の行の順序を逆にするにはどうすればよいですか?


641

テキストファイル(またはstdin)の行の順序を逆にして、各行の内容を保持したいと思います。

つまり、次のように始まります。

foo
bar
baz

私は終わりにしたいと思います

baz
bar
foo

このための標準的なUNIXコマンドラインユーティリティはありますか?


2
行の逆転に関する重要な注意:ファイルの先頭に改行があることを確認してください。そうしないと、入力ファイルの最後の2行が出力ファイルの1行にマージされます(少なくともを使用しますperl -e 'print reverse <>'が、おそらく他の方法にも適用されます)。
jakub.g 2015


また、unix.stackexchange.com / questions / 9356 / …の(古いものの)かなり重複しています。その場合と同様に、unix.stackexchange.comへの移行がおそらく適切です。
mc0e

回答:


444

BSDテール:

tail -r myfile.txt

参照:FreeBSDNetBSDOpenBSDおよびOS Xのマニュアルページ。


120
'-r'オプションはPOSIXに準拠していないことに注意してください。以下のsedおよびawkソリューションは、最も奇抜なシステムでも機能します。

32
Ubuntu 12.04でこれを試したところ、私のバージョンのテール(8.13)に-rオプションがないことがわかりました。代わりに 'tac'を使用してください(以下のMihaiの回答を参照してください)。
オディティー2012

12
チェックマークが下に移動してtacになります。Ubuntu 12/13、Fedora 20、Suse 11でtail -rが失敗する
rickfoosusa '31 / 01/31

3
tail -r〜/ 1〜tail:無効なオプション-r詳細については、「tail --help」を試してください。新しいオプションのように見える
Bohdan 2014

6
特にOPが「標準のUNIX」ユーティリティを要求したので、答えは確かにこれがBSDのみであることを述べるべきです。これはGNUテールに含まれていないため、事実上の標準ではありません。
DanC、2014年

1402

また言及する価値があります:tac(the、ahem、reverse of cat)。coreutilsの一部。

あるファイルを別のファイルに反転する

tac a.txt > b.txt

72
特に、-rオプションなしでtailのバージョンを使用している人に言及する価値があります!(ほとんどのLinuxの人々は-rがないGNUテールを持っているので、GNU tacを持っています)。
oylenshpeegul 2009

11
人々は以前にtacについて言及しましたが、tacはOS Xにインストールされていないようです。Perlで代替を書くのは難しいことではありませんが、本当の私は持っていません。
Chris Lutz、

5
FinkからOS X用のGNU tacを入手できます。BSDテイルではできないこともあるので、GNUテイルも取得したい場合があります。
oylenshpeegul

25
homebrewでOS Xを使用する場合、tacをインストールできますbrew install coreutilsgtacデフォルトでインストール)。
ロバート

3
問題の1つは、ファイルの末尾に新しい行がない場合、最初の2行が1行として結合されることがあります。echo -n "abc\ndee" > test; tac test
CMCDragonkai 2017

161

あります、よく知られているsedのトリック

# reverse order of lines (emulates "tac")
# bug/feature in HHsed v1.5 causes blank lines to be deleted
sed '1!G;h;$!d'               # method 1
sed -n '1!G;h;$p'             # method 2

(説明:バッファを保持するために先頭以外の行を追加し、行をスワップしてバッファを保持し、最後に行を出力します)

または、awkワンライナーから(より高速に実行して):

awk '{a[i++]=$0} END {for (j=i-1; j>=0;) print a[j--] }' file*

思い出せないなら

perl -e 'print reverse <>'

GNUユーティリティを備えたシステムでは、他の答えは単純ですが、すべての世界がGNU / Linuxであるわけではありません...


4
同じソースから:awk '{a [i ++] = $ 0} END {for(j = i-1; j> = 0;)print a [j--]}'ファイル* sedバージョンとawkバージョンの両方が動作します私のbusyboxルーター。'tac'および 'tail -r'にはありません。

8
これが正解だといいのですが。coz sedは常に利用可能ですがtail -r、tac は利用できません。
ryenus

@ryenus:tacメモリに収まらない任意の大きなファイルを処理することが期待されます(ただし、行の長さは制限されています)。このsedようなファイルに対してソリューションが機能するかどうかは不明です。
jfs

ただし、問題のみ:待機する準備をする:-)
AntoineLizéeOct

1
より正確には、sedコードはO(n ^ 2)にあり、大きなファイルの場合は非常に遅くなる可能性があります。したがって、私のawk代替案への賛成、線形。私はperlオプションを試しませんでした。
AntoineLizée2014年

71

コマンドの最後に次のように入力します。 | tac

tacは、あなたが求めていることを正確に実行します。「最後の行を最初にして、各FILEを標準出力に書き込みます」。

tacはcat :-)の反対です。


なぜ彼は?tacコマンドの値を説明してください。これは、同じ主題を検索してしまう可能性のある新しいユーザーに役立ちます。
Nic3500 2018

11
これは本当に受け入れられる答えになるはずです。上記の恥は非常に多くの票を持っています。
joelittlejohn

62

vim使用中の場合

:g/^/m0


4
あなたがそれが何をしたか簡単に説明したなら、私はそれを賛成票を投じます。
mc0e 16

2
ええ、私はそのビットを取得しますが、vimコマンドのさまざまなビットが何をしているかを分析することを意味しました。説明を提供するリンクされた@kenorbの回答を確認しました。
mc0e

5
gは「これをグローバルに実行することを意味します。^は「行の先頭」を意味します。mは「行を新しい行番号に移動する」ことを意味します。0は移動先の行です。0は、「ファイルの先頭、現在の行1の前」を意味します。したがって、「先頭があるすべての行を見つけて、行番号0に移動します。」1行目を見つけて、一番上に移動します。何もしません。次に、2行目を見つけて1行目より上に移動し、ファイルの先頭に移動します。3行目を見つけて、一番上に移動ます。すべての行でこれを繰り返します。最後に、最後の行を先頭に移動して終了します。完了したら、すべての行を逆にしました。
ロノポリス

:gグローバルコマンドは、単に範囲を使用する場合とは異なり、非常に特殊な方法で動作することに注意してください。たとえば、コマンド ":%m0"は行の順序を逆にしませんが、 ":%normal ddggP"は( ":g / ^ / normal ddggP"と同様に)逆になります。素敵なトリックと説明...ええ、トークンを忘れました "詳細については:help:gを参照してください" ...
Nathan Chappell

51
tac <file_name>

例:

$ cat file1.txt
1
2
3
4
5

$ tac file1.txt
5
4
3
2
1

42
$ (tac 2> /dev/null || tail -r)

tacLinuxで機能するを試してください。それが機能しない場合はtail -r、BSDおよびOSX で機能するを試してください。


4
なぜtac myfile.txtでしょうか-何が欠けていますか?
セージ2013年

8
@sage、使用できないtail -r場合にフォールバックするtactacPOSIXに準拠していません。どちらもありませんtail -r。それでも絶対確実というわけではありませんが、これにより、動作する確率が向上します。
slowpoison 2013

わかりました-失敗したときにコマンドを手動/対話式で変更できない場合。私には十分です。
セージ2013

3
tacが利用可能かどうかを確認するには、適切なテストが必要です。tacが利用可能であるが、RAMが不足し、巨大な入力ストリームを消費する途中でスワップする場合 これは失敗し、tail -rストリームの残りの部分の処理に成功して、不正な結果をもたらします。
mc0e 16

@PetrPeller OSX use homebrewについては、Robertによるコメントの上の回答を参照してください。代わりにbrew install coreutils 使用gtactacます。gtacたとえば、クロスプラットフォーム(Linux、OSX)を使用するシェルスクリプトが必要な場合は、別名としてtacを追加します
lacostenycoder

24

次のコマンドを試してください。

grep -n "" myfile.txt | sort -r -n | gawk -F : "{ print $2 }"

:代わりにgawkの文の、私はこのような何かをしたい sed 's/^[0-9]*://g'
bng44270

2
grep -nの代わりに「nl」を使用しないのはなぜですか?
Good Person

3
@GoodPerson、nlデフォルトでは空行の番号付けに失敗します。この-baオプションは一部のシステムで使用できますが、普遍的ではありません(HP / UXが思い浮かびますが、使用しない方がいいと思います)一方で、(この場合は空の)正規表現に一致するすべての行にgrep -n常に番号が付けられます。
ghoti 2015

1
私はgawkの代わりに使用しますcut -d: -f2-
Alexander Stumpf、

17

Just Bash :)(4.0+)

function print_reversed {
    local lines i
    readarray -t lines

    for (( i = ${#lines[@]}; i--; )); do
        printf '%s\n' "${lines[i]}"
    done
}

print_reversed < file

2
bashでの回答とO(n)、および再帰を使用しない(+1可能な場合)の
+1

2
この行-neneneneneneneを含むファイルでこれを試して、人々がのprintf '%s\n'代わりに常に使用することを推奨する理由を確認してくださいecho
mtraceur 2017

@mtraceurこれは一般的な機能なので、今回もそれに同意します。
konsolebox 2017年

11

最も簡単な方法は、tacコマンドを使用することです。tacあるcatのは逆。例:

$ cat order.txt
roger shah 
armin van buuren
fpga vhdl arduino c++ java gridgain
$ tac order.txt > inverted_file.txt
$ cat inverted_file.txt
fpga vhdl arduino c++ java gridgain
armin van buuren
roger shah 

1
この答えが下の答えの前に表示される理由はわかりませんが、それは、 何年も前に投稿されたstackoverflow.com/a/742485/1174784のまとまりです。
anarcat 2015年


3

以下を編集すると、1から10までの数字のランダムにソートされたリストが生成されます。

seq 1 10 | sort -R | tee /tmp/lst |cat <(cat /tmp/lst) <(echo '-------') **...**

ドットはリストを逆にする実際のコマンドに置き換えられます

タック

seq 1 10 | sort -R | tee /tmp/lst |cat <(cat /tmp/lst) <(echo '-------') \
<(tac)

python:sys.stdinで[::-1]を使用

seq 1 10 | sort -R | tee /tmp/lst |cat <(cat /tmp/lst) <(echo '-------') \
<(python -c "import sys; print(''.join(([line for line in sys.stdin])[::-1]))")

3

tacシェルスクリプト内で使用できるクロスOS(つまり、OSX、Linux)ソリューションの場合は、他の人が上記のようにhomebrewを使用し、次のように単にtacをエイリアスします。

libをインストールする

MacOSの場合

brew install coreutils

Linux debianの場合

sudo apt-get update
sudo apt-get install coreutils 

次にエイリアスを追加します

echo "alias tac='gtac'" >> ~/.bash_aliases (or wherever you load aliases)
source ~/.bash_aliases
tac myfile.txt

2

これはBSDとGNUの両方で機能します。

awk '{arr[i++]=$0} END {while (i>0) print arr[--i] }' filename

1

ファイルをその場で変更したい場合は、実行できます

sed -i '1!G;h;$!d' filename

これにより、一時ファイルを作成して元のファイルを削除または名前変更する必要がなくなり、同じ結果になります。例えば:

$tac file > file2
$sed -i '1!G;h;$!d' file
$diff file file2
$

ephemient回答に基づいています。これは、私が望んでいたことはほぼ完了しましたが完全ではありませんでした。


1

n非常に大きなテキストファイルの最後の行を効率的に取得したい場合があります。

私が最初に試したのはですがtail -n 10000000 file.txt > ans.txt、非常に遅いことがわかりました。tailその場所にシーク​​してから、結果を印刷するために戻る必要があるためです。

気づいたら、別のソリューションに切り替えますtac file.txt | head -n 10000000 > ans.txt。今回は、シーク位置が最後から目的の場所に移動するだけで、時間を50%節約できます。

お持ち帰りメッセージ:

オプションがないtac file.txt | head -n n場合に使用tail-rます。


0

最適なソリューション:

tail -n20 file.txt | tac

Stack Overflowへようこそ!このコードスニペットは問題を解決する可能性がありますが、説明を含めると、投稿の質を高めるのに役立ちます。あなたは将来の読者のための質問に答えていることを覚えておいてください、そしてそれらの人々はあなたのコード提案の理由を知らないかもしれません。また、説明コメントでコードを混雑させないようにしてください。これにより、コードと説明の両方が読みにくくなります。
kayess

0

Emacsユーザーの場合:(C-x hファイル全体を選択)、次にM-x reverse-region。また、パーツまたはラインを選択し、それらを元に戻す場合にのみ機能します。


0

面白いアイデアがたくさんあります。しかし、私の考えを試してください。これにテキストをパイプします。

rev | tr '\ n' '〜' | rev | tr '〜' '\ n'

これは、文字「〜」がファイルにないことを前提としています。これは、1961年まで遡るすべてのUNIXシェルで機能するはずです。


-1

私は同じ質問をしましたが、最初の行(ヘッダー)もトップに留まることを望みました。だから私はawkの力を使う必要があった

cat dax-weekly.csv | awk '1 { last = NR; line[last] = $0; } END { print line[1]; for (i = last; i > 1; i--) { print line[i]; } }'

PSはcygwinまたはgitbashでも動作します


1\n20\n19...2\nいうよりは結果になりそう20\n19...\2\n1\nです。
マークブース

-1

あなたがそれを行うことができますvim stdinし、stdout。を使用exしてPOSIXに準拠することもできますvimは単なるのビジュアルモードですex。実際には、あなたが使用することができexvim -evim -E(改善されたexモード)。 vimのようなツールとは異なりsed、ファイルは編集用にバッファsedされますが、ストリームには使用されます。を使用できるawk場合もありますが、手動ですべてを変数にバッファリングする必要があります。

アイデアは次のようにすることです:

  1. stdinから読み取る
  2. 各行について、それを行1に移動します(逆方向に)。コマンドはg/^/m0です。これは、各行についてグローバルに意味しgます。何にでも一致する行の先頭に一致し^ます。アドレス0、つまり1行目の後に移動しますm0
  3. すべてを印刷します。コマンドは%pです。これは、すべての行の範囲を意味し%ます。行を印刷しますp
  4. ファイルを保存せずに強制終了します。コマンドはq!です。これは、終了することを意味しqます。力強く!
# Generate a newline delimited sequence of 1 to 10
$ seq 10
1
2
3
4
5
6
7
8
9
10

# Use - to read from stdin.
# vim has a delay and annoying 'Vim: Reading from stdin...' output
# if you use - to read from stdin. Use --not-a-term to hide output.
# --not-a-term requires vim 8.0.1308 (Nov 2017)
# Use -E for improved ex mode. -e would work here too since I'm not
# using any improved ex mode features.
# each of the commands I explained above are specified with a + sign
# and are run sequentially.
$ seq 10 | vim - --not-a-term -Es +'g/^/m0' +'%p' +'q!'
10
9
8
7
6
5
4
3
2
1
# non improved ex mode works here too, -e.
$ seq 10 | vim - --not-a-term -es +'g/^/m0' +'%p' +'q!'

# If you don't have --not-a-term, use /dev/stdin
seq 10 | vim -E +'g/^/m0' +'%p' +'q!' /dev/stdin

# POSIX compliant (maybe)
# POSIX compliant ex doesn't allow using + sign to specify commands.
# It also might not allow running multiple commands sequentially.
# The docs say "Implementations may support more than a single -c"
# If yours does support multiple -c
$ seq 10 | ex -c "execute -c 'g/^/m0' -c '%p' -c 'q!' /dev/stdin

# If not, you can chain them with the bar, |. This is same as shell
# piping. It's more like shell semi-colon, ;.
# The g command consumes the |, so you can use execute to prevent that.
# Not sure if execute and | is POSIX compliant.
seq 10 | ex -c "execute 'g/^/m0' | %p | q!" /dev/stdin

これを再利用可能にする方法

私が呼び出すスクリプトved(vimエディターのようなsed)を使用して、vimを編集しますstdin。これをvedパスで呼び出されるファイルに追加します。

#!/usr/bin/env sh

vim - --not-a-term -Es "$@" +'%p | q!'

vim +では+'%p' +'q!'10個のコマンドに制限されているため、私はの代わりに1つのコマンドを使用しています。したがって、それらをマージすると、は8個ではなく"$@"9個の+コマンドを持つことができます。

次に、次のことができます。

seq 10 | ved +'g/^/m0'

vim 8がない場合は、ved代わりに次のコードを入力してください。

#!/usr/bin/env sh

vim -E "$@" +'%p | q!' /dev/stdin

-3
rev
text here

または

rev <file>

または

rev texthere

こんにちは、Stack Overflowへようこそ。質問に答えるときは、作者が間違ったことや修正のために何をしたかなど、何らかの説明を含める必要があります。これは、あなたの回答が低品質であると報告されており、現在レビュー中であるためです。「編集」ボタンをクリックして回答を編集できます。
フェデリコグランディ

特に 古いよく答えられた質問に対する新しい答えは、さらに別の答えを追加するための十分な正当化を必要とします。
ガートアーノルド

revはテキストを水平方向にも反転しますが、これは望ましい動作ではありません。
D3l_Gato

-4

tail -rは、ほとんどのLinuxおよびMacOSシステムで機能します

シーケンス1 20 | 尾-r


-9
sort -r < filename

または

rev < filename

7
sort -r入力が既にソートされている場合にのみ機能しますが、ここではそうではありません。rev行ごとの文字を逆にしますが、スコットが要求したものではない行の順序をそのまま維持します。したがって、この答えは実際にはまったく答えではありません。
Alexander Stumpf、2016年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.