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.

pmaipmui
źródło
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' ...)
użytkownik43791
źródło
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.

mikeserv
źródło
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.

Monty Harder
źródło
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.

zła
źródło
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 :-)
ChuckCottrill
źródło
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.

LSerni
źródło
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
terdon
źródło
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.

Gabrer
źródło
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.

kos
źródło
Nie wykluczasz pierwszej linii. Przy NR == 2 drukujesz pierwszy wiersz danych wejściowych, które zostały zapisane r.
xhienne