Jak usunąć pierwsze n wierszy i ostatni wiersz pliku za pomocą poleceń powłoki?


31

Mam plik o nazwie Element_queryzawierający wynik zapytania:

SQL> select count (*) from element;

[Output of the query which I want to keep in my file]

SQL> spool off;

Chcę usunąć 1. linię i ostatnią linię za pomocą polecenia powłoki.


2
Prawdopodobnie najlepiej jest to naprawić wewnątrz SQL * Plus; zamiast generować plik, a następnie próbować przycinać rzeczy, których nie chcesz, możesz po prostu powiedzieć SQL * Plus, aby nie generował tych rzeczy na początek. Jedno podejście opisano w sekcji „Tworzenie pliku płaskiego” na docs.oracle.com/cd/A84870_01/doc/sqlplus.816/a75664/ch44.htm ; inne podejście opisano na stronie stackoverflow.com/q/2299375/978917 .
— ruakh

Odpowiedzi:


48

Za pomocą GNU sed:

sed -i '1d;$d' Element_query

Jak to działa :

  • -iopcja edycji samego pliku. Możesz również usunąć tę opcję i przekierować dane wyjściowe do nowego pliku lub innego polecenia, jeśli chcesz.
  • 1dusuwa pierwszy wiersz ( 1aby działać tylko w pierwszym wierszu, daby go usunąć)
  • $dusuwa ostatni wiersz ( $aby działać tylko na ostatnim wierszu, daby go usunąć)

Idąc dalej :

  • Możesz także usunąć zakres. Na przykład 1,5dusunąłby pierwsze 5 wierszy.
  • Możesz także usunąć każdą linię, która zaczyna się od SQL>użycia instrukcji/^SQL> /d
  • Możesz usunąć każdą pustą linię za pomocą /^$/d
  • Na koniec możesz połączyć dowolną instrukcję, oddzielając ją średnikiem ( statement1;statement2;satement3;...) lub określając je osobno w wierszu poleceń ( -e 'statement1' -e 'statement 2' ...)

Jeśli jego trzecia linia do usunięcia ... to muszę użyć 3d zamiast 1d? jeśli jego trzeci wiersz od ostatniego do usunięcia ... to jakie będzie polecenie?
— pmaipmui

Jak usunąć trzeci wiersz z ostatniego przy użyciu poleceń powłoki?
— pmaipmui

@Nainita Możesz określić zakres ( 1,3dusunie pierwsze trzy linie), ale na koniec jest to trochę trudniejsze. W zależności od tego, co chcesz, lepiej byłoby użyć tego: sed -i '/^SQL> /d' Element_querydo usuwania linii, które zaczynają się SQL> bez względu na to, gdzie jest w pliku.
— user43791,

@Nainita - zapoznaj się z moją odpowiedzią na temat arbitralnego zliczania ogonów - oferuje dwa rozwiązania usuwania linii zliczania względem końca pliku. Jeden jest sedliniowcem - który będzie działał do usuwania dowolnych liczb wierszy z początku i końca pliku. Lepiej jednak, dopóki dane wejściowe są zwykłymi plikami, to tylko zgrupowanie pojedynczych danych wejściowych w dwóch headprocesach - jest to najszybszy sposób to zrobić zwykle.
— mikeserv

Kiedyś sed -i '1d' table-backup.sqlusuwałem pierwszy wiersz pliku tekstowego sql
— David Thomas

8

głowa; głowa

{   head -n[num] >/dev/null
    head -n[num]
}  <infile >outfile

Za pomocą powyższego można określić pierwszą liczbę linii do usunięcia z nagłówka wyjścia z pierwszym headpoleceniem oraz liczbę linii do zapisania outfileza pomocą drugiego. Zazwyczaj robi to również szybciej niż sed- zwłaszcza gdy dane wejściowe są duże - pomimo konieczności dwóch wywołań. Gdzie sedna pewno powinny być preferowane jest jednak to, że w przypadku <infilejest nie regularny, lseekable plik - bo będzie to zazwyczaj nie działa prawidłowo w tym przypadku, ale sedmoże obsługiwać wszystkie modyfikacje wyjściowych w jednym, skryptów procesu.

W GNU headmożesz również użyć -formy ujemnej dla [num]drugiego polecenia. W takim przypadku następujące polecenie usunie pierwszy i ostatni wiersz z danych wejściowych:

{   head -n1 >/dev/null
    head -n-1
}  <infile >outfile

LUB z POSIX sed:

Powiedzmy na przykład, że czytałem 20 linii i chciałem usunąć pierwsze 3 i ostatnie 7. Gdybym zdecydował się to zrobić w / sed, zrobiłbym to z buforem ogona. Najpierw dodam trzy i siedem dla całkowitej liczby pasków wynoszącą dziesięć, a następnie:

seq 20 | sed -ne:n -e '3d;N;1,10bn' -eP\;D

To przykład, który usuwa pierwsze 3 i ostatnie 7 wierszy z wejścia. Chodzi o to, że możesz buforować tyle wierszy, ile chcesz usunąć z końca tekstu wejściowego w przestrzeni wzoru na stosie, ale Pzrewidować tylko pierwszą z nich dla każdej wciągniętej linii.

  • Na liniach 1,10 sed Pnic nie rintuje, ponieważ dla każdego z nich układa dane wejściowe w przestrzeni wzorów linia po linii w bpętli ranch.
  • W trzeciej linii cały sedstos jest deletowany - a więc pierwsze 3 linie są usuwane z wyjścia za jednym zamachem.
  • Kiedy sedosiągnie $ostatni wiersz wejścia i spróbuje wyciągnąć Next, uderza EOF i całkowicie przestaje przetwarzać. Ale w tym czasie przestrzeń wzorów zawiera wszystkie linie 14,20- z których żadna nie została jeszcze Pzaznaczona i nigdy nie jest.
  • Co drugi wiersz sed Płączy się tylko do pierwszego występującego \newline w przestrzeni wzorów i Dusuwa go przed rozpoczęciem nowego cyklu z pozostałymi - lub następnymi 6 liniami wprowadzania. Siódma linia jest ponownie dołączana do stosu za pomocą Npolecenia ext w nowym cyklu.

I tak z seqwyniku (który składa się z 20 kolejno ponumerowanych linii) , sedwypisuje tylko:

4
5
6
7
8
9
10
11
12
13

Staje się to problematyczne, gdy liczba linii, które chcesz usunąć z ogona wejściowego, jest duża - ponieważ sedwydajność jest wprost proporcjonalna do wielkości przestrzeni wzorcowej. Jednak w wielu przypadkach jest to realne rozwiązanie - a POSIX określa sedprzestrzeń wzorcową do obsługi co najmniej 4 kb przed zniszczeniem.


1
GNU tailobsługuje również rozszerzoną tail -n+<num>składnię oznaczającą „start od linii <num>”
— UloPe

4

Nie zamierzam odpowiadać, jak usunąć pewną liczbę wierszy. Zamierzam zaatakować problem w ten sposób:

grep -v '#SQL>' Element_query >outfile

Zamiast zliczać wiersze, eliminuje polecenia SQL, rozpoznając monity. To rozwiązanie można następnie uogólnić na inne pliki wyjściowe sesji SQL z większą liczbą poleceń niż tylko dwie.


Lubię to. Nie wiem dużo o SQL - ale czy nie ma szans, że monity pojawią się na początku linii wyjściowych?
— mikeserv

4

edjest „standardowym edytorem tekstu” i powinien być dostępny w systemach, które nie mają GNU sed. Został pierwotnie zaprojektowany jako edytor tekstu, ale dobrze nadaje się do pisania skryptów.

printf '%s\n' 1d '$d' w q | ed Element_query

1dusuwa pierwszy wiersz pliku $d(cytowany, aby powłoka nie myślała, że ​​jest zmienną) usuwa ostatni wiersz, wzapisuje plik i qkończy pracę ed. printfsłuży tutaj do formatowania poleceń ed- po każdej z nich musi znajdować się nowa linia; istnieją oczywiście inne sposoby osiągnięcia tego celu.


3

Istnieje kilka sposobów usuwania linii wiodących i końcowych z pliku.

Możesz użyć, awkponieważ obsługuje zarówno dopasowywanie wzorów, jak i liczenie linii,

#you need to know length to skip last line, assume we have 100 lines
awk 'NR>1 && NR<100 {print $0};' < inputfile
#or
awk '/SQL/ {next}; {print $0;};' < inputfile |awk 'NR>1&& NR<10 {print $0};'

Możesz użyć, grep -vaby wykluczyć linie, których nie chcesz według wzoru, i możesz dopasować wiele wzorów za pomocą -Eopcji,

grep -v -E "SQL>" < inputfile > outputfile

Możesz używać headi tailprzycinać określoną liczbę linii,

lines=$((`wc -l < inputfile`-2)) #how many lines in file, less 2
head -n-1 < inputfile | head -n$lines > outputfile
#or
tail -n+2 < inputfile | head -n$lines > outputfile

Możesz użyć vi/vimi usunąć pierwszą i ostatnią linię,

vi inputfile
:1
dd
:$
dd
:w! outputfile
:x

możesz użyć skryptu perla, pominąć pierwszy wiersz, zapisać każdy wiersz, wydrukować, gdy pojawi się następny wiersz,

#left as exercise for the reader :-)

1
Dla tych head, których tak naprawdę nie potrzebujesz, i w rzeczywistości lepiej nie używać go, jeśli możesz uciec. Gdy to zrobisz head | head- oba procesy mogą działać równolegle, oba przetwarzają również praktycznie wszystkie te same dane nadmiarowo. Jeśli to zrobisz { head >dump; head >save; } <in, pomiń tylko przesunięcie - pierwszy odczytuje 10 linii do, >dumpa drugi odczytuje kolejne 10 linii do >save.
— mikeserv

3

Lepiej byłoby ci służyć, odcinając polecenia SQL. Możesz to zrobić na dwa sposoby:

  1. Jeśli masz absolutną pewność, że sekwencja „ SQL>” nie występuje nigdzie indziej w danych wyjściowych,

    grep -v -F 'SQL> ' < infile > outfile
  2. Jeśli nie jesteś tak pewien,

    grep -v '^SQL> .*;$' < infile > outfile

Druga wersja jest wolniejsza, ale dokładniejsza: zignoruje linie dokładnie zaczynające się od „SQL>” i kończące się średnikiem, które wydają się opisywać linie, które chcesz wyeliminować.

Jednak lepiej byłoby nie umieszczać tego dodatkowego wyjścia w pliku na początek. Większość systemów SQL ma na to sposób. Nie znam się zbyt dobrze na Oracle, ale może ta odpowiedź może być pomocna.


3

Możesz wybrać linie między zakresem w awk(zakłada się, że wiesz, ile jest linii):

awk 'NR>1 && NR < 3' file

Lub w Perlu:

perl -ne 'print if $.>1 && $.<3' file

Jeśli nie wiesz, ile jest linii, możesz obliczyć je w locie, używając grep(nie liczą się puste linie, użyj również, grep -c '' fileaby je policzyć):

awk -vm="$(grep -c . file2.txt)" 'NR>1 && NR<m' file2.txt

3

Wypróbuj to rozwiązanie:

tail -n +2 name_of_file | head -n-1

Dostosowywanie

Można łatwo dostosować go usunąć n pierwsze linie zmieniając +2od tail;
lub usunąć ostatnie n wierszy Zmiana -1z head.


To rozwiązanie jest nieprawidłowe, ponieważ drukuje pierwszą linię.
— xhienne

1
@xhienne Przepraszamy, to był błąd. Napisałem 1 zamiast 2 jako parametr „ogona”. Teraz działa, dzięki! :)
— Gabrer

1

Używanie awk:

< inputfile awk 'NR>1 {print r}; {r=$0}' > outputfile
  • < inputfile: Przekierowuje zawartość inputfiledo awk„sstdin
  • > outputfile: Przekierowuje treść awk„s stdoutdooutputfile
  • NR>1: wykonuje następujące działania tylko wtedy, gdy liczba przetwarzanego rekordu jest większa niż 1
  • {print r}: drukuje zawartość zmiennej r
  • {r=$0}: przypisuje zawartość przetwarzanego rekordu do zmiennej r

Tak więc przy pierwszym wykonaniu awkskryptu pierwszy blok akcji nie jest wykonywany, podczas gdy drugi blok akcji jest wykonywany, a zawartość rekordu jest przypisywana do zmiennej r; przy drugim wykonaniu wykonywany jest pierwszy blok akcji i rwypisywana jest zawartość zmiennej (tak więc drukowany jest poprzedni rekord); powoduje to wydruk każdego przetworzonego wiersza, ale pierwszego i ostatniego.


Nie wykluczasz pierwszej linii. Przy NR == 2 drukujesz pierwszy wiersz danych wejściowych, które zostały zapisane r.
— xhienne
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.