GNU/Linux >> Znalost Linux >  >> Linux

Jak extrahovat/změnit řádky v textovém souboru, jehož data jsou rozdělena do polí?

Jak mohu manipulovat s daty založenými na poli z příkazového řádku? Například

  • Jak mohu vytisknout pouze řádky, jejichž N-té pole je foo? ?
  • Jak mohu vytisknout pouze řádky, jejichž N-té pole není foo ?
  • Jak mohu vytisknout pouze řádky, jejichž N-té pole odpovídá foo ?
  • Jak mohu změnit pole N na foo ?

Existuje standardní přístup nebo sada nástrojů, která usnadňuje manipulaci s daty založenými na poli na systémech *nix?

Přijatá odpověď:

Při práci s poli lze použít dva základní přístupy:i) použít nástroj, který polím rozumí; ii) použijte regulární výraz. První z nich je obvykle robustnější a jednodušší.

Mnoho z běžně dostupných nástrojů na *nix je buď výslovně navrženo tak, aby se vypořádalo s poli, nebo mají šikovné triky, které to usnadní.

1. Použijte nástroj, který rozumí polím

1.1 awk

Klasickým nástrojem je zde awk . Automaticky rozdělí každý vstupní řádek na pole (oddělovač polí je ve výchozím nastavení prázdný, ale lze jej změnit pomocí -F flag) a pole jsou pak dostupná pro awk skript jako $n kde n je číslo pole. První pole je $1 , druhý $2 atd.

  • Tisk řádků, jejichž 3. pole je foo .

    awk '$3=="foo"' file
    

    Změna oddělovače na :

    awk -F":" '$3=="foo"' file
    

    Výchozí akce awk je tisknout. Výše uvedené příkazy tedy vytisknou všechny řádky, jejichž 3. pole je foo . Při použití -F , můžete nastavit libovolné oddělovače polí a dokonce použít regulární výrazy.

  • Jak mohu vytisknout pouze řádky, jejichž 3. pole není foo ?

    awk '$3!="foo"' file
    
  • Jak mohu vytisknout pouze řádky, jejichž 3. pole odpovídá foo ?

    Pokud pouze hledáte pole, která odpovídají vzoru (například foo odpovídá foobar ), použijte ~ místo == :

    awk '$3~/foo/' file
    
  • Jak mohu vytisknout pouze řádky, jejichž 3. pole neodpovídá foo ?

    awk '$3!~/foo/' file
    
  • Jak mohu změnit 3. pole na foo ?

    awk '$3="foo"' file
    

1.2 Perl

Další možností je perl jednovrstvé. Stejně jako awk je i Perl plnohodnotný skriptovací jazyk, ale lze jej spustit také jako program příkazového řádku, který jako vstup používá skript. Jeho chování je upraveno přepínači příkazového řádku, z nichž nejdůležitější pro tuto otázku jsou:

  • -e :skript, který perl by měl běžet;
  • -n :čtení vstupního souboru řádek po řádku;
  • -p :vytiskne každý vstupní řádek po použití skriptu daného -e;
  • -l :odstranit koncové nové řádky z každého vstupního řádku a přidat nový řádek do každého print zavolat;
  • -a :awk-mode, rozdělit každý vstupní řádek do pole @F;
  • -F :oddělovač pole pro -a .

Důležitý rozdíl oproti awk je to perl 's -a přepínač rozdělí soubory do pole. V Perlu začínají pole na 0, ne na 1. To znamená, že 2. pole je ve skutečnosti $F[1] a ne $F[2] . S ohledem na toto vše, perl ekvivalenty výše uvedených jsou:

  • Tisk řádků, jejichž 3. pole je foo .

    perl -ane 'print if $F[2] eq "foo"' file
    

    Změna oddělovače na :

    perl -F":" -ane 'print if $F[2] eq "foo"' file
    

    Na rozdíl od awk , perl nelze použít regulární výrazy jako oddělovače polí. Musí to být konkrétní znak nebo řetězec.

  • Jak mohu vytisknout pouze řádky, jejichž 3. pole není foo ?

    perl -ane 'print unless $F[2] eq "foo"' file
    
  • Jak mohu vytisknout pouze řádky, jejichž 3. pole odpovídá foo ?

    perl -ane 'print if $F[2]=~/foo/' file
    
  • Jak mohu vytisknout pouze řádky, jejichž 3. pole neodpovídá foo ?

    perl -lane 'print unless $F[2]=~/foo/' file
    
  • Jak mohu změnit 3. pole na foo ?

    Tenhle je v Perlu trochu těžkopádnější. Obvyklý přístup je změnit hodnotu v @F pole a poté pole vytiskněte. S jednoduchými soubory oddělenými mezerou je to snadné:

    perl -lane '$F[2]="foo"; print "@F"' file
    

    S jiným oddělovačem se budete muset join pole. V opačném případě bude vytištěno odděleně:

    perl -F: -lane '$F[2]="foo"; print join ":",@F' file
    

2. Používejte regulární výrazy

Myšlenka je zde použít regulární výraz (zkráceně „regex“), který definuje pozici cílového řetězce v řádku. Například v souboru, jehož pole jsou oddělena : , můžeme najít 2. pole tak, že porovnáme vše až do 1. : (1. pole) a poté hledejte druhé:

^[^:]*:[^:]*:

Tento regulární výraz znamená:

  • ^ :začátek řádku;
  • [^] :negovaná třída znaků. [^:] znamená „cokoli kromě : “;
  • * :0 nebo více z předchozího vzoru;
  • : :doslovný :;

Dohromady to znamená, že první [^:]* je první pole a druhé je druhé pole. Je zřejmé, že to není příliš praktické, pokud hledáte 14. pole, ale může být užitečné pro jednodušší věci. Jak to tedy implementujeme, abychom manipulovali s našimi daty? Existují různé nástroje, které to umí; v těchto příkladech budu používat sed ale velmi podobné věci můžete dělat s awk , perl nebo python .

  • Jak mohu vytisknout pouze řádky, jejichž 2. pole je foo ?

    sed -n '/^[^:]*:foo:/p' file
    

    -n potlačí normální výstup a /regex/p znamená „vytisknout všechny řádky, které odpovídaly regulárnímu výrazu.

  • Jak mohu vytisknout pouze řádky, jejichž 2. pole není foo ?

    sed '/^[^:]*:foo:/d' file
    

    Logická inverze k výše uvedenému. Zde je /regex/d znamená „smazat všechny řádky, kterým odpovídá regulární výraz.

  • Jak mohu vytisknout pouze řádky, jejichž 2. pole odpovídá foo ?

    sed -n '/^[^:]*:[^:]*foo/p' file
    
  • Jak mohu vytisknout pouze řádky, jejichž 2. pole neodpovídá foo ?

    sed '/^[^:]*:[^:]*foo/d' file
    
  • Jak mohu změnit 2. pole na foo ?

    sed 's/([^:]*:)[^:]*/1foo/' file 
    

    Nebo, protože sed substituce může přímo řešit výskyt vzorů jeho opakováním s jednoduchým číselným příznakem:

    sed 's/[^:]*/foo/2' file
    

Linux
  1. Jak odstranit více náhodných řádků z textového souboru pomocí Sed?

  2. Převedení více řádků do jednoho řádku odděleného čárkou

  3. Jak rozdělit jeden textový soubor do více souborů *.txt?

  1. Jak extrahovat textovou část binárního souboru v linux/bash?

  2. jak zkopírovat řádky 10 až 15 souboru do jiného souboru v unixu?

  3. Jak převést konkrétní text ze seznamu na velká písmena?

  1. Jak odstranit duplicitní řádky uvnitř textového souboru?

  2. Co jsou režimy Vim? Jak je změnit?

  3. Jak zobrazit určité řádky z textového souboru v Linuxu?