Отримайте конкретний рядок з текстового файлу, використовуючи лише скрипт оболонки


100

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

Поки в Інтернеті я бачив лише такі речі, як sed, (я можу використовувати лише sh -not bash або sed або щось подібне). Мені потрібно це робити лише за допомогою базового сценарію оболонки.

cat file | while read line
    do
       #do something
    done

Я знаю, як перебирати рядки, як показано вище, але що робити, якщо мені просто потрібно отримати вміст певного рядка


чи знаєте ви номер рядка?
— Мехул Ратод

1
Тоді ви отримуєте рахувати.
— Ігнасіо Васкес-Абрамс

так, номер рядка 5 @MehulRathod
— GangstaGraham

3
Чому це catдобре, але sedні? В цьому немає сенсу.
— Вільям Перселл

5
Тому що ніхто не може сказати "ні" cat. Ау ... мило cat!

Відповіді:


204

sed:

sed '5!d' file

awk:

awk 'NR==5' file

Що з командою sh, я не можу використовувати sed, awk. Я повинен зробити це більш зрозумілим у питанні.
— GangstaGraham

@GangstaGraham Ви сказали, що знаєте, як перебрати рядки, як щодо додавання лічильника? якщо лічильник досягне вашого цільового номера рядка, дістаньте лінію та розірвіть цикл. чи допомагає це?
— Кент

4
@KanagaveluSugumar прочитав інформацію про сторінку sed. 5!dозначає видалити всі рядки, крім 5. оболонки var можливо, вам потрібні подвійні лапки.
— Кент

13
Я б запропонував додати ще один варіант: sed -n 5pдля новачків це здається більш логічним, оскільки -nозначає "відсутність результатів за замовчуванням" і pозначає "друк", і немає потенційно заплутаної згадки про видалення (коли люди говорять про файли, видалення рядків має тенденцію до означають щось інше).
— Йосип Родін

1
@JosipRodin ви праві, -n '5p'працює і для цієї проблеми. Різниця тут полягає в тому, що 5!dви можете додати, -iщоб записати зміни у файл. однак, з -n 5pвами sed -n '5p' f > f2&& mv f2 fзнову, з цього питання, я згоден з вашою думкою.
— Кент

21

Якщо припустити line, це змінна, яка містить потрібний номер рядка, якщо ви можете використовувати headі tail, то це досить просто:

head -n $line file | tail -1

Якщо ні, це має працювати:

x=0
want=5
cat lines | while read line; do
  x=$(( x+1 ))
  if [ $x -eq "$want" ]; then
    echo $line
    break
  fi
done

Це -eqпорівняння призначене для цілих чисел, тому потрібно номер рядка, а не вміст рядка ( $line). Це потрібно виправити, визначаючи, наприклад, want=5перед циклом, а потім використовуючи -eqпорівняння на $want. [перейшов з відхиленої редакції]
— Йосип Родін

1
@JosipRodin Я зробив незалежну пропозицію щодо редагування на основі вашого коментаря, оскільки я згоден з цим. Сподіваємось, цього разу він не буде відхилений.
— Віктор Заманян

15

Ви можете використовувати sed -n 5p file .

Ви також можете отримати діапазон, наприклад, sed -n 5,10p file.


11

Найкращий метод виконання

sed '5q;d' file

Тому що sedперестає читати будь-які рядки після 5-го

Оновіть експеримент від містера Роджера Дуека

Я встановив wcanadian-insane (6.6MB) і порівняв sed -n 1p / usr / share / dict / words і sed '1q; d' / usr / share / dict / words за допомогою команди time; перший займав 0,043, другий лише 0,002, тому використання 'q' безумовно, поліпшення продуктивності!


1
Про це також часто пишуть:sed -n 5q
— Вільям Перселл

3
Мені подобається це рішення, тому що sedпісля 5-го перестає читати будь-які рядки.
— Ентоні Геоґеган

1
Я встановив wcanadian-insane (6.6MB) і порівняв sed -n 1p /usr/share/dict/wordsта sed '1q;d' /usr/share/dict/wordsвикористовував timeкоманду; перший займав 0,043, другий лише 0,002, тому використання 'q' безумовно, поліпшення продуктивності!
— Роджер

5

Якщо ви, наприклад, хочете отримати рядки від 10 до 20, ви можете використовувати кожен із цих двох методів:

head -n 20 york.txt | tail -11

або

sed -n '10,20p' york.txt 

p вище командні стенди для друку.

Ось що ви побачите: введіть тут опис зображення


2

Стандартний спосіб зробити подібну річ - це використання зовнішніх інструментів. Забороняти використання зовнішніх інструментів під час написання сценарію оболонки є абсурдом. Однак якщо ви дійсно не хочете використовувати зовнішні інструменти, ви можете надрукувати рядок 5 за допомогою:

i=0; while read line; do test $((++i)) = 5 && echo "$line"; done < input-file

Зауважте, що це надрукує логічний рядок 5. Тобто, якщо вони input-fileмістять продовження рядків, вони будуть рахуватися як один рядок. Ви можете змінити цю поведінку, додавши -rдо команди read. (Яка, мабуть, бажана поведінка.)


1
$((++i))виявляється башизмом; якщо ОП обмежена у використанні зовнішніх інструментів, я не припускаю, що вони матимуть доступ до більш ніж простого/bin/sh
— Йосип Родін

@JosipRodin Ні, це функція POSIX (але підтримка ++приростів спеціально позначена як необов'язкова).
— tripleee

@tripleee це не працює з сучасним тире як / bin / sh, тому я б не покладався на нього.
— Йосип Родін

Але просте вирішення, як і $((i+=1))роботи в Dash, теж.
— трійка

$(($i+1))це просте вирішення, про яке я думав.
— Йосип Родін

1

Паралельно з відповіддю Вільяма Перселла , ось проста конструкція, яка повинна працювати навіть в оригінальній оболонці Bourne v7 (і, таким чином, також місцях, де Bash недоступний).

i=0
while read line; do
    i=`expr "$i" + 1`
    case $i in 5) echo "$line"; break;; esac
done <file

Зауважте також оптимізацію breakвиходу з циклу, коли ми отримали потрібну лінію.


0

Мені особливо не сподобалася відповідь.

Ось як я це зробив.

# Convert the file into an array of strings
lines=(`cat "foo.txt"`)

# Print out the lines via array index
echo "${lines[0]}"
echo "${lines[1]}"
echo "${lines[5]}"

-1

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

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

seq 5 | perl -ne 'print if $. ~~ [1, 4, 5]'але smartmatch експериментальний, і його використання
— Сорін

Ні одне з інших рішень не є таким стислим, або допускає велику гнучкість. (Чому здається, що все, що економить час і полегшує все, "відлякує" розумними людьми? Чи ми всі повинні дивитись на екрани цілий день?)
— dagelf

-1
line=5; prep=`grep -ne ^ file.txt | grep -e ^$line:`; echo "${prep#$line:}"

3
Ви могли б хоч трохи описати, чому цей твір зробити його зрозумілішим для людини, яка поставила запитання?
— тед

Отже, перший греп вибирає всі рядки, додаючи номери рядків на їх початку. Тоді другий греп вибирає конкретний рядок, порівнюючи номер рядка на початку. І нарешті номер рядка обрізається від початку рядка в ехо.
— Одер

Це як складне, так і неефективне порівняно з тим sed -n 5p, що, звичайно, все ж можна оптимізувати до чогось подібногоsed -n '5!d;p;q'
— tripleee
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.