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


85

Напевно, всі знають корисні утиліти cmd line для Linux headта tail. headдозволяє друкувати перші X рядки файлу, tailробить те саме, але друкує кінець файлу. Яка хороша команда для друку середини файлу? щось на зразок middle --start 10000000 --count 20(надрукуйте 10'000'000-й до 10-ї тисячі рядків).

Я шукаю щось, що дозволить ефективно працювати з великими файлами. Я спробував, tail -n 10000000 | head 10і це жахливо повільно.


5
можливий дублікат serverfault.com/questions/101900/…
Кайл Брандт

Відповіді:


111
sed -n '10000000,10000020p' filename

Можливо, ви зможете трохи прискорити це так:

sed -n '10000000,10000020p; 10000021q' filename

У цих командах опція -nвикликає sed"придушення автоматичного друку простору шаблону". p«Друк [s] поточний простір шаблону» команди і qкоманда «Відразу кинути [з] СЄПН сценарію без обробки більше введення ...» Цитата з sed manсторінки .

До речі, ваша команда

tail -n 10000000 filename | head 10

починається з десятимільйонного рядка з кінця файлу, тоді як ваша "середня" команда, здається, починається з десятимільйонного початку, що було б еквівалентно:

head -n 10000010 filename | tail 10

Проблема полягає в тому, що для несортованих файлів із рядками змінної довжини будь-який процес повинен буде пройти через файл підрахунку нових рядків. Неможливо цього скоротити.

Якщо, однак, файл відсортований (наприклад, файл журналу із часовими позначками) або має фіксовані рядки довжини, то ви можете шукати у файлі на основі позиції байтів. У цьому прикладі файл журналу, ви могли б зробити бінарний пошук в діапазоні часу , як мій сценарій Python тут * робить. У випадку файлу з фіксованою довжиною запису це дуже просто. Ви просто шукаєте linelength * linecountсимволів у файлі.

* Я зберігаю сенс опублікувати ще одне оновлення цього сценарію. Можливо, я обійдусь цим днями.


Ось sedверсія Чарльза middleфункції: middle() { local s=$1 c=$2; shift 2; sed -n "$s,$(($s + $c -1))p; $(($s + $c))q" "$@"; }. Він обробляє декілька файлових аргументів, назви файлів з пробілами тощо. Кілька файлів обробляються разом так, як ніби вони були введені таким же чином, sedяк і зазвичай (тому середина 1000 100 file1 file2 простягатиметься в кінці першого файлу до початку другого, якщо перший має менше 1100 рядків).
Денніс Вільямсон

Функцію в моєму попередньому коментарі можна викликати параметром імені файлу: middle startline count filenameабо декількома іменами файлів: middle startline count file1 file2 file3або з перенаправленням: middle startline count < filenameабо в трубі: some_command | середня кількість початкових ліній` абоcat file* | middle startline count
Денніс Вільямсон,

Чи не повинно бути команда "sed"? Я не можу змусити його працювати з backtick, але він добре працює з єдиною цитатою.
Ян Хантер

@beanland: Так, це помилка друку. Я це виправив. Дякую.
Денніс Вільямсон

1
@kev: Я додав пояснення до своєї відповіді.
Денніс Вільямсон

28

Я з'ясував таке використання sed

sed -n '10000000,+20p'  filename

Сподіваюся, комусь це корисно!


Приємно знати, що існує альтернатива останньому рядковому аргументу, запропонованому Деннісом: рядок вважається другим sed -nаргументом, що робить його досить читабельним.
користувач3123159

Приклад використання: extract_lines(){sed -n "$1,+$2p" <file>}який пише в stdout.
користувач3123159

4

Це моя вперше публікація тут! У будь-якому випадку, це легко. Скажімо, ви хочете вивести рядок 8872 з вашого файлу під назвою file.txt. Ось як це зробити:

cat -n file.txt | grep '^ * 8872'

Тепер питання - знайти 20 рядків після цього. Для цього ви робите

cat -n file.txt | grep -A 20 '^ * 8872'

Для рядків навколо або перед цим див. Прапори -B та -C у посібнику зі звіту.


Хоча це технічно правильно і цікавий спосіб зробити це на файлі з досить великим розміром, мені цікаво його ефективність при роботі з файлами розміру, про який запитує плакат.
Дженні Д

Кілька рядків: cat -n file.txt | grep "^ \ s \ + (10 \ | 20 \ | 30) \ s \ +"
Джеффрі Найт

cat -n file.txt | grep '^ *1'вивести всі лінії, які мають 1 на правій стороні. Як вивести рядок 1 за допомогою цієї техніки? Я знаю, що можу очолити -n 1 .... але як використовувати grep?
Sean87

1

Відповідь Денніса - це шлях. Але, використовуючи лише голову та хвіст, під удар:

mid () {head -n $ [$ 1 + $ 2] | хвіст -n $ 2; }

Це сканує перші два рядки $ 1 + $ 2, тому набагато гірше, ніж відповідь Денніса. Але вам не потрібно запам’ятовувати всі ці букви sed, щоб використовувати його…


Використання $[...]застаріло, принаймні в Bash. Також вам не вистачає параметра файлу.
Денніс Вільямсон

@Dennis: Відсутній параметр: ви повинні використовувати це на stdin, відповідно до вказівки middle 10 10 < /var/log/auth.log.
Чарльз Стюарт

1

Використовуйте наступну команду, щоб отримати конкретний діапазон рядків

awk 'NR < 1220974{next}1;NR==1513793{exit}' debug.log | tee -a test.log

Тут debug.log - мій файл, який складається з недоліків рядків, і я використовував для друку рядків від 1220974 номер рядка до 1513793 до файлу test.log. сподіваємось, це буде корисно для зйомки діапазону ліній.


Та сама відповідь, що і сервер defaultfault.com/a/641252/140016 . Захищений.
Мисливець на оленів

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

0

Рубінова версія.

ruby -pe 'next unless $. > 10000000 && $. < 10000020' < filename.txt

Це може бути корисним комусь. Рішення з «sed», що надаються Dennis та Dox, дуже приємні, навіть тому, що це здається швидшим.




0

Якщо ви знаєте нумери рядків, скажіть, що ви хочете отримати рядок 1, 3 і 5 з файлу, скажіть / etc / passwd:

perl -e 'while(<>){if(++$l~~[1,3,5]){print}}' < /etc/passwd

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