Как удалить первые n строк и последнюю строку файла с помощью команд оболочки?

31

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

SQL> select count (*) from element;

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

SQL> spool off;

Я хочу удалить 1-ю строку и последнюю строку с помощью команды оболочки.

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

Ответы:

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' ...)
user43791
источник
Если его 3-я строка для удаления ... тогда я должен использовать 3d вместо 1d? если его 3-ю строку от последней удалить ... тогда какой будет команда?
pmaipmui
Как удалить третью строку из последней, используя команды оболочки?
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

С помощью вышеприведенного вы можете указать первое число строк для удаления заголовка выходных данных с первой headкомандой и количество строк для записи outfileсо второй. Это также обычно делает это быстрее, чем, sedособенно когда ввод велик, несмотря на то, что требуется два вызова. Где sedопределенно должны быть предпочтительными , хотя, в том случае, если <infileэто не обычный, lseekable файл - потому что это будет , как правило , не работают как положено в этом случае, но 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стеки 'ы dвыбраны - и поэтому первые 3 строки удаляются из вывода одним махом.
  • Когда sedдостигает $последней строки ввода и пытается выдвинуть Next, он достигает EOF и полностью останавливает обработку. Но в то время пространство образца содержит все линии 14,20- ни одна из которых еще не была Pнабрана и никогда не была.
  • На каждой другой строке sed Pпечатается только до первой \nвстречной линии в пространстве шаблона и Dвыбирается одинаково перед началом нового цикла с тем, что осталось - или следующими 6 строками ввода. Седьмая строка снова добавляется в стек командой Next в новом цикле.

И так, из seqвыходных данных (то есть 20 последовательно пронумерованных строк) , sedтолько печатает:

4
5
6
7
8
9
10
11
12
13

Это становится проблематичным, когда число строк, которые вы хотите вырезать из хвоста ввода, велико - потому что sedпроизводительность прямо пропорциональна размеру пространства шаблонов. Тем не менее, во многих случаях это жизнеспособное решение - и POSIX sedзадает пространство шаблонов для обработки не менее 4 КБ перед перебором.

mikeserv
источник
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- за каждой должна следовать новая строка; Конечно, есть и другие способы сделать это.

evilsoup
источник
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 :-)
ChuckCottrill
источник
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, но, возможно, этот ответ может быть полезным.

LSerni
источник
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

настройка

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

Gabrer
источник
Это решение неверно, так как печатает первую строку.
xhienne
1
@xhienne Извините, это была ошибка. Я написал 1 вместо 2 в качестве параметра «хвоста». Теперь это работает, спасибо! :)
Gabrer
1

Использование awk:

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

Таким образом, при первом выполнении awkсценария первый блок действий не выполняется, а второй блок действий выполняется, и содержимое записи назначается переменной r; при втором выполнении выполняется первый блок действий и rпечатается содержимое переменной (поэтому печатается предыдущая запись); это приводит к печати каждой обработанной строки, кроме первой и последней.

кос
источник
Вы не исключаете первую строку. При NR == 2 вы печатаете первую строку ввода, которая хранится в r.
xhienne