Saya ingin membalik urutan baris dalam file teks (atau stdin), menjaga konten setiap baris.
Jadi, yaitu, dimulai dengan:
foo
bar
baz
Saya ingin berakhir dengan
baz
bar
foo
Apakah ada utilitas baris perintah UNIX standar untuk ini?
Saya ingin membalik urutan baris dalam file teks (atau stdin), menjaga konten setiap baris.
Jadi, yaitu, dimulai dengan:
foo
bar
baz
Saya ingin berakhir dengan
baz
bar
foo
Apakah ada utilitas baris perintah UNIX standar untuk ini?
Jawaban:
Juga layak disebutkan: tac
(the, ahem, kebalikan dari cat
). Bagian dari coreutils .
tac a.txt > b.txt
brew install coreutils
(menginstal sebagai gtac
default).
echo -n "abc\ndee" > test; tac test
.
Ada trik sed yang terkenal :
# 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
(Penjelasan: tambahkan baris non-awal untuk menahan buffer, swap line and hold buffer, cetak baris di akhir)
Atau (dengan eksekusi lebih cepat) dari awk one-liners :
awk '{a[i++]=$0} END {for (j=i-1; j>=0;) print a[j--] }' file*
Jika Anda tidak dapat mengingatnya,
perl -e 'print reverse <>'
Pada sistem dengan utilitas GNU, jawaban lain lebih sederhana, tetapi tidak semua dunia adalah GNU / Linux ...
tail -r
dan tidak .
tac
diharapkan untuk menangani file besar sembarang yang tidak muat di memori (panjang jalur masih terbatas). Tidak jelas apakah sed
solusi berfungsi untuk file seperti itu.
pada akhir perintah Anda masukkan:
| tac
tac melakukan persis apa yang Anda minta, itu "Tulis setiap FILE ke output standar, baris terakhir terlebih dahulu."
tac adalah kebalikan dari kucing :-).
tac
perintah, ini berguna untuk pengguna baru yang mungkin akhirnya mencari subjek yang sama.
Jika Anda sedang vim
digunakan
:g/^/m0
$ (tac 2> /dev/null || tail -r)
Coba tac
, yang berfungsi di Linux, dan jika itu tidak berfungsi gunakan tail -r
, yang bekerja pada BSD dan OSX.
tac myfile.txt
- apa yang saya lewatkan?
tail -r
jaga tac
- jaga jika tidak tersedia. tac
tidak kompatibel dengan POSIX. Tidak juga tail -r
. Masih tidak aman, tetapi ini meningkatkan peluang bekerja.
tac
tersedia, tetapi kehabisan RAM dan menukar setengah jalan melalui mengkonsumsi aliran input raksasa. Gagal, dan kemudian tail -r
berhasil memproses sisa aliran memberikan hasil yang salah.
brew install coreutils
dan gunakan gtac
di tempat tac
dan jika Anda lebih suka menambahkan tac sebagai alias untuk gtac
jika misalnya Anda ingin skrip shell yang menggunakannya lintas platform (Linux, OSX)
Coba perintah berikut:
grep -n "" myfile.txt | sort -r -n | gawk -F : "{ print $2 }"
sed 's/^[0-9]*://g'
nl
secara default akan gagal ke nomor baris kosong. The -ba
pilihan tersedia pada beberapa sistem, bukan tidak universal (HP / UX datang ke pikiran, walaupun saya berharap itu tidak akan) sedangkan grep -n
akan selalu jumlah setiap baris yang cocok dengan (dalam hal ini mengosongkan) regex.
cut -d: -f2-
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
-nenenenenenene
dan menyaksikan alasan mengapa orang merekomendasikan selalu menggunakan printf '%s\n'
bukan echo
.
Metode paling sederhana adalah menggunakan tac
perintah. tac
adalah cat
's terbalik. Contoh:
$ 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
Saya sangat suka jawaban " tail -r ", tetapi jawaban gawk favorit saya adalah ....
gawk '{ L[n++] = $0 }
END { while(n--)
print L[n] }' file
mawk
Ubuntu 14.04 LTS - berfungsi, jadi tidak spesifik untuk GNU. +1
n++
dapat diganti denganNR
EDIT berikut menghasilkan daftar nomor yang diurutkan secara acak dari 1 hingga 10:
seq 1 10 | sort -R | tee /tmp/lst |cat <(cat /tmp/lst) <(echo '-------') **...**
di mana titik-titik diganti dengan perintah aktual yang membalikkan daftar
tac
seq 1 10 | sort -R | tee /tmp/lst |cat <(cat /tmp/lst) <(echo '-------') \
<(tac)
python: using [:: - 1] di sys.stdin
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]))")
Untuk solusi lintas OS (yaitu OSX, Linux) yang mungkin digunakan tac
di dalam skrip shell gunakan homebrew seperti yang telah disebutkan di atas, maka hanya alias tac seperti:
Instal lib
Untuk MacOS
brew install coreutils
Untuk linux debian
sudo apt-get update
sudo apt-get install coreutils
Kemudian tambahkan alias
echo "alias tac='gtac'" >> ~/.bash_aliases (or wherever you load aliases)
source ~/.bash_aliases
tac myfile.txt
Jika Anda ingin memodifikasi file di tempat, Anda dapat menjalankan
sed -i '1!G;h;$!d' filename
Ini menghilangkan kebutuhan untuk membuat file sementara dan kemudian menghapus atau mengganti nama aslinya dan memiliki hasil yang sama. Sebagai contoh:
$tac file > file2
$sed -i '1!G;h;$!d' file
$diff file file2
$
Berdasarkan jawaban dengan singkat , yang melakukan hampir, tetapi tidak cukup, apa yang saya inginkan.
Itu terjadi pada saya bahwa saya ingin mendapatkan n
baris terakhir dari file teks yang sangat besar secara efisien .
Hal pertama yang saya coba adalah tail -n 10000000 file.txt > ans.txt
, tetapi ternyata sangat lambattail
harus mencari ke lokasi dan kemudian bergerak kembali untuk mencetak hasilnya.
Ketika saya menyadari itu, saya beralih ke solusi lain: tac file.txt | head -n 10000000 > ans.txt
. Kali ini, posisi pencarian hanya perlu bergerak dari ujung ke lokasi yang diinginkan dan menghemat waktu 50% !
Pesan rumah:
Gunakan tac file.txt | head -n n
jika Anda tail
tidak memiliki -r
opsi.
Solusi terbaik:
tail -n20 file.txt | tac
Untuk pengguna Emacs: C-x h
(pilih seluruh file) lalu M-x reverse-region
. Juga berfungsi hanya untuk memilih bagian atau garis dan mengembalikannya.
Saya memiliki pertanyaan yang sama, tetapi saya juga ingin baris pertama (header) tetap di atas. Jadi saya perlu menggunakan kekuatan 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 juga berfungsi di cygwin atau gitbash
1\n20\n19...2\n
daripada 20\n19...\2\n1\n
.
Anda dapat melakukannya dengan vim
stdin
dan stdout
. Anda juga dapat menggunakan ex
untuk menjadi POSIX compliant . vim
hanyalah mode visual untuk ex
. Bahkan, Anda dapat menggunakannya ex
dengan vim -e
atau vim -E
( ex
mode yang ditingkatkan ).
vim
berguna karena tidak seperti alat seperti sed
itu buffer file untuk diedit, sementara sed
digunakan untuk stream. Anda mungkin dapat menggunakan awk
, tetapi Anda harus secara manual buffer semuanya dalam suatu variabel.
Idenya adalah untuk melakukan hal berikut:
g/^/m0
. Ini berarti secara global, untuk setiap baris g
; cocok dengan awal baris, yang cocok dengan apa pun ^
; pindahkan setelah alamat 0, yaitu baris 1m0
.%p
. Ini berarti untuk rentang semua lini %
; cetak garisp
.q!
. Ini berarti berhenti q
; dengan paksa !
.# 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
Cara membuat ini dapat digunakan kembali
Saya menggunakan skrip yang saya panggil ved
(vim editor like sed
) untuk menggunakan vim untuk mengedit stdin
. Tambahkan ini ke file yang disebut ved
di jalur Anda:
#!/usr/bin/env sh
vim - --not-a-term -Es "$@" +'%p | q!'
Saya menggunakan satu +
perintah, bukan +'%p' +'q!'
, karena vim membatasi Anda hingga 10 perintah. Jadi menggabungkan mereka memungkinkan "$@"
untuk memiliki 9+
perintah, bukan 8.
Maka Anda dapat melakukan:
seq 10 | ved +'g/^/m0'
Jika Anda tidak memiliki vim 8, masukkan ini ved
sebagai gantinya:
#!/usr/bin/env sh
vim -E "$@" +'%p | q!' /dev/stdin
rev
text here
atau
rev <file>
atau
rev texthere
sort -r < filename
atau
rev < filename
sort -r
hanya berfungsi jika input sudah diurutkan, yang tidak terjadi di sini. rev
membalikkan karakter per baris tetapi menjaga urutan garis tetap utuh yang juga bukan apa yang diminta Scotty. Jadi jawaban ini sebenarnya tidak ada jawaban sama sekali.
perl -e 'print reverse <>'
tetapi mungkin juga berlaku untuk metode lain).