Bir dosyadan birden fazla boş satır nasıl kaldırılır?


14

Not almak için kullandığım bazı metin dosyalarım var - sadece düz metin, genellikle sadece cat >> file. Bazen yeni bir konu / düşünce çizgisi belirtmek için boş bir çizgi ya da iki (sadece geri dön - yeni çizgi karakteri) kullanıyorum. Her oturumun sonunda, dosyayı Ctrl+ ile kapatmadan önce D, oturumları ayırmak için genellikle çok sayıda (5-10) boş satır (dönüş tuşu) eklerim.

Bu çok zekice bir şey değil, ama bu amaçla benim için çalışıyor. Ben do sonuna kadar ancak çok ve gereksiz boş satırlar dolu, ben kaldırmak için bir yol arıyorum böylece ekstra hatları (çoğu). Doğrudan birkaç seçenekle kullanılabilecek bir Linux komutu (kesme, yapıştırma, grep, ...?) Var mı? Alternatif olarak, herkes istediğimi yapacak bir sed, awk veya perl (gerçekten herhangi bir script dilinde gerçekten, sed veya awk tercih etsem de) için bir fikri var mı? C ++ 'da (aslında kendim yapabileceğim) bir şey yazmak, aşırıya kaçmış gibi görünüyor.

Vaka # 1: İhtiyacım olan iki (3 veya daha fazla) ardışık boş satırdan fazlasını kaldıracak ve sadece iki boş satırla değiştirecek bir komut dosyası / komut. Yine de, birden fazla satırı (2 veya daha fazla) kaldırmak ve / veya birden fazla boş satırı yalnızca bir boş satırla değiştirmek de ince ayar yapılabilirse iyi olurdu.

Durum # 2: İki metin satırı arasında tek bir boş satırı kaldıracak bir komut dosyası / komut da kullanabilirim , ancak olduğu gibi birden fazla boş satır bırakabilirsiniz (boş satırlardan birini kaldırmak da kabul edilebilir).



2
tamamen farklı bir soru @ l0b0 (başka bir bir olan vimbir, ile boş satır değiştirmekti bir boş satır).
Stéphane Chazelas

Yanıtlar:


14

Dava 1:

awk '!NF {if (++n <= 2) print; next}; {n=0;print}'

Durum 2:

awk '!NF {s = s $0 "\n"; n++; next}
     {if (n>1) printf "%s", s; n=0; s=""; print}
     END {if (n>1) printf "%s", s}'

Sed yerine awk için +1
Rob

Bu kullanım durumu sık sık tekrarlandığından, bir komut dosyası oluşturmanızı öneririm.
ChuckCottrill

15

uniqBirden çok boş satır örneğini boş bir satıra daraltmak için kullanabilirsiniz , ancak aynı ve birbirinin altındaysa, metin içeren satırları da daraltır.


6

Dava 1:

perl -i -ane '$n=(@F==0) ? $n+1 : 0; print if $n<=2'

Durum 2:

perl -i -ane '$n=(@F==0) ? $n+1 : 0; print $n==2 ? "\n$_" : $n==1 ? "" : $_ '

+1 perl ftw! Awk (muhtemelen) bunun için kanoniktir, ancak (DRY) beni bu gibi tekrarlanan kullanım durumları için komut dosyaları yazmaya zorlar.
ChuckCottrill

3

GNU sed ile Durum # 1'e şu şekilde hitap edebilirsiniz:

sed -r ':a; /^\s*$/ {N;ba}; s/( *\n *){2,}/\n\n/'

Yani, desen alanında boş çizgiler toplayın ve üç veya daha fazla çizgi varsa, iki satıra indirin.

Durum 2'de olduğu gibi tek aralıklı satırları birleştirmek için bunu şu şekilde yapabilirsiniz:

sed -r '/^ *\S/!b; N; /\n *$/!b; N; /\S *$/!b; s/\n *\n/\n/'

Veya yorumlanmış biçimde:

sed -r '
  /^ *\S/!b        # non-empty line
  N                # 
  /\n *$/!b        # followed by empty line
  N                # 
  /\S *$/!b        # non-empty line
  s/\n *\n/\n/     # remove the empty line
'

1

Bu çözüm, dosyadaki son boş satırlarla da ilgilenir:

sed -r -n '
  /^ *$/!{p;b}  # non-blank line - print and next cycle
  h             # blank line - save it in hold space
  :loop
  $b end        # last line - go to end
  n             # read next line in pattern space
  /^ *$/b loop  # blank line - loop to next one
  :end          # pattern space has non-blank line or last blank line
  /^ *$/{p;b}   # last blank line: print and exit
  H;x;p         # non-blank line: print hold + pattern space and next cycle
'

0

Anthon'un "uniq" kullanma önerisini takiben ...

Öndeki, arkadaki ve yinelenen boş satırları kaldırın.

# Get large random string.
rand_str=; while [[ ${#rand_str} -lt 40 ]]; do rand_str=$rand_str$RANDOM; done

# Add extra lines at beginning and end of stdin.
(echo $rand_str; cat; echo $rand_str) |

# Convert empty lines to random strings.
sed "s/^$/$rand_str/" |

# Remove duplicate lines.
uniq |

# Remove first and last line.
sed '1d;$d' |

# Convert random strings to empty lines.
sed "s/$rand_str//"

Uzun bir satırda:

(rand_str=; while [[ ${#rand_str} -lt 40 ]]; do rand_str=$rand_str$RANDOM; done; (echo $rand_str; cat; echo $rand_str) | sed "s/^$/$rand_str/" | uniq | sed '1d;$d' | sed "s/$rand_str//")

Veya sadece "cat -s" kullanın.

Daha etkili olduğunu düşündüğüm mevcut kabuk bağlamında kalmak için parantezden kıvırcık parantezlere geçtim. Kıvırcık parantezlerin son komuttan sonra noktalı virgül gerektirdiğini ve ayırma için bir boşluk gerektiğini unutmayın.

# Add extra blank lines at beginning and end.
# These will be removed in final step.
{ echo; cat; echo; } |

# Replace multiple blank lines with a single blank line.
cat -s |

# Remove first and last line.
sed '1d;$d'

Tek bir satırda.

{ { echo; cat; echo; } | cat -s | sed '1d;$d'; }

0

Gönderilen çözümler bana biraz şifreli görünüyordu. İşte Python 3.6'daki çözüm:

#!/usr/bin/env python3

from pathlib import Path                                                                                                                                                              
import sys                                                                                                                                                                            
import fileinput                                                                                                                                                                      


def remove_multiple_blank_lines_from_file(path, strip_right=True): 
    non_blank_lines_out_of_two_last_lines = [True, True] 
    for line in fileinput.input(str(path), inplace=True): 
        non_blank_lines_out_of_two_last_lines.pop(0) 
        non_blank_lines_out_of_two_last_lines.append(bool(line.strip())) 
        if sum(non_blank_lines_out_of_two_last_lines) > 0: 
            line_to_write = line.rstrip() + '\n' if strip_right else line 
            sys.stdout.write(line_to_write)


def remove_multiple_blank_lines_by_glob(rglob='*', path=Path('.'), strip_right=True): 
    for p in path.rglob(rglob): 
        if p.is_file(): 
            try:
                remove_multiple_blank_lines_from_file(p, strip_right=strip_right)
            except Exception as e:
                print(f"File '{p}' was not processed due the error: {e}")


if __name__ == '__main__':
    remove_multiple_blank_lines_by_glob(sys.argv[1], Path(sys.argv[2]), next(iter(sys.argv[3:]), None) == '--strip-right')

İşlevleri bir yorumlayıcıdan çağırabilir veya kabuktan aşağıdaki gibi çalıştırabilirsiniz:

$ ./remove_multiple_lines.py '*' /tmp/ --strip-right
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.