Her satırın içeriğini koruyarak, bir metin dosyasındaki (veya stdin) satırların sırasını tersine çevirmek istiyorum.
Yani, yani:
foo
bar
baz
Sonunda istiyorum
baz
bar
foo
Bunun için standart bir UNIX komut satırı yardımcı programı var mı?
Her satırın içeriğini koruyarak, bir metin dosyasındaki (veya stdin) satırların sırasını tersine çevirmek istiyorum.
Yani, yani:
foo
bar
baz
Sonunda istiyorum
baz
bar
foo
Bunun için standart bir UNIX komut satırı yardımcı programı var mı?
Yanıtlar:
Ayrıca bahsetmeye değer: tac
(ahem, tersi cat
). Coreutils'in bir parçası .
tac a.txt > b.txt
brew install coreutils
( gtac
varsayılan olarak kurulumlar ) kullanarak kurabilirsiniz .
echo -n "abc\ndee" > test; tac test
.
Orada tanınmış sed hileler :
# 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
(Açıklama: arabelleği tutmak için başlangıçta olmayan satırın başına ekle, hattı değiştir ve arabayı beklet, sonunda satırda yazdır)
Alternatif olarak (daha hızlı uygulama ile) awk tekli gömleklerden :
awk '{a[i++]=$0} END {for (j=i-1; j>=0;) print a[j--] }' file*
Bunu hatırlayamıyorsanız,
perl -e 'print reverse <>'
GNU yardımcı programlarına sahip bir sistemde, diğer yanıtlar daha basittir, ancak tüm dünya GNU / Linux değildir ...
tail -r
ve tac.
tac
belleğe sığmayan keyfi büyük dosyaları işlemesi beklenir (satır uzunluğu yine de sınırlıdır). sed
Çözümün bu tür dosyalar için çalışıp çalışmadığı belirsizdir .
komutunuzun sonuna şunu koyun:
| tac
tac tam olarak istediğini yapar, "Her bir DOSYAYI standart çıktıya yaz, önce son satır."
tac kedinin tam tersidir :-).
tac
komutun değerini açıklayın , bu aynı konuyu arayabilecek yeni kullanıcılar için yararlıdır.
İçinde olmak olur vim
kullanılmak
:g/^/m0
$ (tac 2> /dev/null || tail -r)
tac
Linux üzerinde çalışan ve bu işe yaramazsa tail -r
BSD ve OSX üzerinde çalışan deneyin .
tac myfile.txt
- neyi özlüyorum?
tail -r
durumunda tac
mevcut değildir. tac
POSIX uyumlu değil. İkisi de değil tail -r
. Hala kusursuz değil, ama bu işlerin çalışma olasılığını artırır.
tac
, ancak RAM biterse ve dev bir giriş akışı tüketerek yarıya kadar değiştirin. Başarısız olur ve daha sonra tail -r
yanlış bir sonuç vererek akışın geri kalanını işlemeyi başarır.
brew install coreutils
kullanın ve tercihiniz takma ad olarak ekleyin ve örneğin çapraz platform (Linux, OSX) kullanan bir kabuk betiği istiyorsanızgtac
tac
gtac
Aşağıdaki komutu deneyin:
grep -n "" myfile.txt | sort -r -n | gawk -F : "{ print $2 }"
sed 's/^[0-9]*://g'
nl
varsayılan olarak boş satırları numaralandıramaz. Bu -ba
seçenek bazı sistemlerde mevcuttur, evrensel değildir (HP / UX akla gelir, ancak istemesem de), oysa grep -n
her zaman (bu durumda boş) normal ifadeyle eşleşen her satırı numaralar .
cut -d: -f2-
Sadece 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
ve insanların neden her zaman printf '%s\n'
yerine kullanmasını önerdiğine tanık olun echo
.
En basit yöntem tac
komutu kullanmaktır . tac
olan cat
bireyin ters. Misal:
$ 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
Gerçekten " kuyruk -r " yanıtı gibi, ama benim en sevdiğim gawk cevap ....
gawk '{ L[n++] = $0 }
END { while(n--)
print L[n] }' file
mawk
Ubuntu 14.04 LTS ile test edilmiştir - çalışır, bu nedenle GNU awk'ye özgü değildir. +1
n++
ile değiştirilebilirNR
Aşağıdakileri DÜZENLE , 1'den 10'a kadar rastgele sıralı bir sayı listesi oluşturur:
seq 1 10 | sort -R | tee /tmp/lst |cat <(cat /tmp/lst) <(echo '-------') **...**
noktaların yerini, listeyi tersine çeviren gerçek komutla değiştirir
tac
seq 1 10 | sort -R | tee /tmp/lst |cat <(cat /tmp/lst) <(echo '-------') \
<(tac)
python: sys.stdin'de [:: - 1] kullanımı
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]))")
Kullanabilecek çapraz OS (yani OSX, Linux) çözümü için tac
Bir kabuk komut dosyasının içinde yukarıda belirtildiği gibi homebrew kullanın, sonra sadece takma ad bu şekilde:
Lib yükle
MacOS için
brew install coreutils
Linux debian için
sudo apt-get update
sudo apt-get install coreutils
Ardından takma ad ekleyin
echo "alias tac='gtac'" >> ~/.bash_aliases (or wherever you load aliases)
source ~/.bash_aliases
tac myfile.txt
Dosyayı yerinde değiştirmek istiyorsanız,
sed -i '1!G;h;$!d' filename
Bu, geçici bir dosya oluşturma gereğini ortadan kaldırır ve ardından orijinali siler veya yeniden adlandırır ve aynı sonuca sahiptir. Örneğin:
$tac file > file2
$sed -i '1!G;h;$!d' file
$diff file file2
$
İstediğim neredeyse, ama tam olarak değil, ephemient'in cevabına dayanarak .
Bana n
çok büyük bir metin dosyasının son satırlarını verimli bir şekilde almak istiyorum .
Denediğim ilk şey tail -n 10000000 file.txt > ans.txt
, ama çok yavaş buldum, çünkü tail
konumu aramak zorunda ve sonra sonuçları yazdırmak için geri hareket ediyor.
Ben bunu fark, ben başka bir çözüme geçiş: tac file.txt | head -n 10000000 > ans.txt
. Bu kez, arama pozisyonunun sadece sondan istenen yere gitmesi gerekiyor ve % 50 zaman tasarrufu sağlıyor !
Eve mesaj atın:
Kullan tac file.txt | head -n n
senin eğer tail
yok -r
seçeneği.
En iyi çözüm:
tail -n20 file.txt | tac
Emacs kullanıcıları için: C-x h
(tüm dosyayı seçin) ve ardından M-x reverse-region
. Ayrıca yalnızca parçaları veya çizgileri seçmek ve bunları geri almak için çalışır.
Aynı soruyu sordum, ama ilk satırın da (başlık) üstte kalmasını istedim. Bu yüzden awk gücünü kullanmalıydım
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 ayrıca cygwin veya gitbash'ta da çalışır
1\n20\n19...2\n
değil gibi görünüyor 20\n19...\2\n1\n
.
Bunu vim
stdin
ve ile yapabilirsiniz stdout
. POSIX uyumluex
olmak için de kullanabilirsiniz . sadece görsel modudur . Aslında, veya (gelişmiş mod) ile kullanabilirsiniz .
yararlıdır, çünkü bu gibi araçların aksine dosyayı düzenleme için arabelleğe alırken , akışlar için kullanılır. Kullanabilirsinizvim
ex
ex
vim -e
vim -E
ex
vim
sed
sed
awk
, ancak bir değişkendeki her şeyi manuel olarak arabelleğe almanız gerekir.
Fikir aşağıdakileri yapmaktır:
g/^/m0
. Bu, küresel olarak, her satır için g
; herhangi bir şeyle eşleşen çizginin başlangıcıyla eşleşir ^
; 1. adres olan 0 adresinden sonra taşıyın m0
.%p
. Bu, tüm hatların aralığı için anlamına gelir %
; çizgiyi yazdırın p
.q!
. Bu, bırakma anlamına gelir q
; zorla !
.# 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
Bu nasıl yeniden kullanılabilir hale getirilir
Düzenlemek için vim kullanmak için çağırdığım bir komut dosyası ved
(vim editörü gibi sed
) kullanıyorum stdin
. Bunu yolunuzda adlandırılan bir dosyaya ved
ekleyin:
#!/usr/bin/env sh
vim - --not-a-term -Es "$@" +'%p | q!'
Bunun +
yerine bir komut kullanıyorum +'%p' +'q!'
, çünkü vim sizi 10 komutla sınırlandırıyor. Böylece onları birleştirmek "$@"
9+
, 8 yerine komutuna .
Sonra şunları yapabilirsiniz:
seq 10 | ved +'g/^/m0'
Eğer vim 8'iniz yoksa, bunu ved
yerine koyun :
#!/usr/bin/env sh
vim -E "$@" +'%p | q!' /dev/stdin
rev
text here
veya
rev <file>
veya
rev texthere
sort -r < filename
veya
rev < filename
sort -r
yalnızca giriş zaten sıralanmışsa çalışır, bu durum burada böyle değildir. rev
satır başına karakterleri tersine çevirir, ancak satır sırasını olduğu gibi tutar. Yani bu cevap aslında hiç cevap değil.
perl -e 'print reverse <>'
ancak muhtemelen diğer yöntemler için de geçerlidir).