Як видалити перші n рядків і останній рядок файлу за допомогою команд оболонки?


31

У мене є файл з іменем, Element_queryщо містить результат запиту:

SQL> select count (*) from element;

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

SQL> spool off;

Я хочу видалити перший рядок і останній рядок за допомогою команди shell.


2
Вам, мабуть, найкраще виправити це всередині SQL * Plus; замість того, щоб генерувати файл, а потім намагатися обрізати речі, які вам не потрібні, ви можете просто сказати SQL * Plus не створювати цей матеріал для початку. Один із підходів описаний у розділі "Створення плоского файлу" за адресою docs.oracle.com/cd/A84870_01/doc/sqlplus.816/a75664/ch44.htm ; інший підхід описаний на сайті stackoverflow.com/q/2299375/978917 .
ruakh

Відповіді:


48

Використання GNU sed:

sed -i '1d;$d' Element_query

Як це працює :

  • -iопція редагування самого файлу. Ви також можете видалити цю опцію і, якщо хочете, перенаправити вихід на новий файл або іншу команду.
  • 1dвидаляє перший рядок ( 1діяти лише в першому рядку, dщоб видалити його)
  • $dвидаляє останній рядок ( $діяти лише в останньому рядку, dщоб видалити його)

Далі:

  • Ви також можете видалити діапазон. Наприклад, 1,5dбуде видалено перші 5 рядків.
  • Ви також можете видалити кожен рядок, який починається з SQL>використання оператора/^SQL> /d
  • Ви можете видалити кожен порожній рядок за допомогою /^$/d
  • Нарешті, ви можете поєднати будь-який вислів, відокремивши їх крапкою з комою ( statement1;statement2;satement3;...) або вказавши їх окремо в командному рядку ( -e 'statement1' -e 'statement 2' ...)

Якщо його 3-й рядок видалити ... тоді мені доведеться використовувати 3d замість 1d? якщо його третій рядок з останнього видалити ... то що буде командою?
pmaipmui

Як видалити 3-й рядок з останнього за допомогою команд оболонки?
pmaipmui

@Nainita Ви можете вказати діапазон ( 1,3dвидалить перші три рядки), але це трохи складніше для кінця. Залежно від того, що ви хочете, вам може бути краще скористатися цим: sed -i '/^SQL> /d' Element_queryвидалити рядки, які починаються з SQL> того місця, де він знаходиться у файлі.
user43791

@Nainita - дивіться мою відповідь тут щодо довільних підрахунків хвостів - він пропонує два рішення для зняття ліній підрахунку відносно кінця файлу. Один - це sedодин-вкладиш - який буде працювати для зняття довільних підрахунків рядків з голови та хвоста файлу. Хоча краще, якщо введення є звичайним файлом, просто групувати один вхід у два headпроцеси - це найшвидший спосіб зробити це зазвичай.
mikeserv

Я раніше sed -i '1d' table-backup.sqlвидаляв перший рядок текстового файлу sql
Девід Томас

8

голова; голова

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

За допомогою вищесказаного ви можете вказати перше число рядків, яке слід відкреслити від голови виводу w / першої headкоманди, і кількість рядків, до яких слід записати outfileдругу. Зазвичай це робиться швидше, ніж, sedособливо, коли вхід великий, незважаючи на те, що потрібно два виклики. Де, sedбезумовно, слід віддати перевагу, - це у випадку, якщо <infileце не звичайний файл , який можна шукати - оскільки це, як правило, не працює за призначенням у тому випадку, але sedможе обробляти всі модифікації виводу в одному сценарії.

За допомогою GNU headви можете також використовувати -негативну форму для [num]другої команди. У такому випадку наступна команда зніме перший і останній рядки з введення:

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

АБО з POSIX sed:

Скажімо, наприклад, я читав введення з 20 рядків і хотів зняти перші 3 та останні 7. Якщо я вирішив це зробити w / sed, я би зробив це з хвостовим буфером. Я б спершу склав три і сім за загальної кількості смужок десяти, а потім зробив:

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

Це приклад, який знімає з введення перші 3 та останні 7 рядків. Ідея полягає в тому, що ви можете буферувати стільки ліній, скільки хочете, щоб зняти з хвоста введення в просторі шаблону на стеку, але лише Pнакреслити перший з них для кожного стягнутого рядка.

  • У рядках 1,10 sed Pнічого не вказується, тому що для кожного з них він укладає вхід у простір шаблонів по рядку в bциклі ранчо.
  • У 3-му рядку всі стеки sed's dвибрані - і тому перші 3 рядки позбавляються від виходу одним махом.
  • Коли sedдоходить до $останнього рядка введення і намагається втягнути зовнішній Nудар, він потрапляє на EOF і припиняє обробку цілком. Але в цей час простір шаблону містить усі рядки 14,20- жоден з яких ще не був Pроздрукований і ніколи не є.
  • У будь-якому іншому рядку sed Pвказується лише до першої \nлінії, що виникає в просторі шаблону, і Dвибирається однаково, перш ніж починати новий цикл із тим, що залишається - або наступними 6 рядками введення. 7-й рядок знову додається до стеку командою Next у новому циклі.

І так, з seqвиходу «S (який є 20 послідовно пронумерованих рядків) , sedтільки відбитки:

4
5
6
7
8
9
10
11
12
13

Це стає проблематичним, коли кількість ліній, які ви бажаєте зняти з хвоста введення, велика - тому sedщо продуктивність прямо пропорційна розміру простору шаблону. Однак, в багатьох випадках це життєздатне рішення - і POSIX розраховує sedпростір шаблону, щоб обробляти принаймні 4 кбіт перед тим, як перебирати його.


1
gnu tailтакож підтримує розширений tail -n+<num>синтаксис, що означає "почати з рядка <num>"
UloPe

4

Я не збираюся відповідати, як видалити ряд рядків. Я буду атакувати проблему таким чином:

grep -v '#SQL>' Element_query >outfile

Замість підрахунку рядків він усуває команди SQL шляхом розпізнавання підказок. Потім це рішення можна узагальнити для інших вихідних файлів сеансів SQL з більшою кількістю команд, ніж лише дві.


Мені це подобається. Я мало знаю про SQL - але чи немає шансів, що підказки з’являться на чолі його вихідних рядків інакше?
mikeserv

4

edє "стандартним текстовим редактором" і повинен бути доступний у системах, які не мають GNU sed. Спочатку він був розроблений як текстовий редактор, але він добре підходить до сценаріїв.

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

1dвидаляє перший рядок файлу, $d(цитується так, що оболонка не думає, що це змінна) видаляє останній рядок, wзаписує файл і qзакриває ed. printfтут використовується для форматування команд для ed- за кожною з них повинен бути новий рядок; Звичайно, є й інші способи досягти цього.


3

Існує кілька способів видалити провідні та кінцеві рядки з файлу.

Ви можете використовувати, awkяк він обробляє як узгодження шаблонів, так і підрахунок рядків,

#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};'

Ви можете використовувати grep -vдля виключення ліній, які ви не хочете, за шаблоном, і ви можете зіставити декілька шаблонів за допомогою -Eпараметра,

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

Ви можете використовувати headта tailобрізати певні лінійки,

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

Ви можете використовувати vi/vimта видаляти перший та останній рядки,

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

ви можете використовувати сценарій perl, пропустити перший рядок, зберегти кожен рядок, надрукувати, коли отримаєте наступний рядок,

#left as exercise for the reader :-)

1
Для цих headтруб вам насправді не потрібна труба, і насправді краще взагалі не користуватися нею, якщо ви зможете піти з нею. Коли ви це робите head | head- хоча обидва процеси можуть працювати одночасно, вони також обробляють практично всі однакові дані. Якщо ви робите замість цього, { head >dump; head >save; } <inви пропускаєте лише за зміщенням - перший читає 10 рядків, >dumpа другий читає наступні 10 рядків >save.
mikeserv

3

Вам набагато краще послужити, відрізавши команди SQL. Це можна зробити двома способами:

  1. Якщо ви абсолютно впевнені, що послідовність " SQL>" не зустрічається більше ніде у виході,

    grep -v -F 'SQL> ' < infile > outfile
  2. Якщо ви не так впевнені,

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

Друга версія більш повільна, але точніша: вона буде ігнорувати рядки, які точно починаються з "SQL>" і закінчуються крапкою з комою, які, схоже, описують лінії, які ви хочете усунути.

Однак було б краще не ставити цей додатковий вихід у файл для початку. Більшість систем SQL мають певний спосіб зробити це. Я не надто розмовляю з Oracle, але, можливо, ця відповідь може бути корисною.


3

Ви можете вибрати рядки між діапазоном у awk(це означає, що ви знаєте, скільки рядків існує):

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

Або в Perl:

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

Якщо ви не знаєте, скільки рядків є, ви можете обчислити його на льоту, використовуючи grep(зауважте, що це не буде рахувати порожні рядки, використовуйте grep -c '' fileдля їх підрахунку):

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

3

Спробуйте це рішення:

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

Настроювання

Ви можете легко адаптувати його для видалення п перших рядків змінюючи +2з tail;
або видалити останні п рядків , що змінюють -1з head.


Це рішення є невірним, оскільки друкує перший рядок.
xhienne

1
@xhienne Вибачте, це була помилка. Я написав 1 замість 2 як параметр "хвіст". Тепер це працює, дякую! :)
Габрер

1

Використання awk:

< inputfile awk 'NR>1 {print r}; {r=$0}' > outputfile
  • < inputfile: переспрямовує вміст inputfileдо awk'sstdin
  • > outputfile: переспрямовує вміст awk's stdoutдоoutputfile
  • NR>1: виконує такі дії, лише якщо кількість запису, який обробляється, перевищує 1
  • {print r}: друкує вміст змінної r
  • {r=$0}: призначає зміну запису, який обробляється, змінної r

Отже, при першому виконанні awkскрипту перший блок дій не виконується, тоді як другий блок дій виконується і зміст запису присвоюється змінній r; при другому виконанні виконується перший блок дій і rдрукується вміст змінної (так друкується попередній запис); це призводить до друку кожного обробленого рядка, але першого та останнього.


Ви не виключаєте перший рядок. На NR == 2 ви друкуєте перший рядок вводу, який зберігається в r.
xhienne
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.