Команда Shell / Bash для получения n-й строки STDOUT

133

Есть ли какая-либо команда bash, которая позволит вам получить n-ю строку STDOUT?

То есть, что-то, что займет это

$ ls -l
-rw-r--r--@ 1 root  wheel my.txt
-rw-r--r--@ 1 root  wheel files.txt
-rw-r--r--@ 1 root  wheel here.txt

и сделайте что-то вроде

$ ls -l | magic-command 2
-rw-r--r--@ 1 root  wheel files.txt

Я понимаю, что это было бы плохой практикой при написании сценариев, предназначенных для повторного использования, НО при работе с оболочкой день за днем ​​мне было бы полезно фильтровать мой STDOUT таким образом.

Я также понимаю, что это будет полутривиальная команда для записи (буфер STDOUT, возврат определенной строки), но я хочу знать, есть ли там какая-то команда стандартная команда, которая будет доступна без того, чтобы я сбросил script на место.

Теги:
sed
stdout

13 ответов

228
Лучший ответ

Используя sed, просто для разнообразия:

ls -l | sed -n 2p

Используя эту альтернативу, которая выглядит более эффективной, так как она перестает считывать ввод при печати требуемой строки, может генерировать SIGPIPE в процессе подачи, что может в свою очередь генерировать сообщение об ошибке:

ls -l | sed -n -e '2{p;q}'

Я видел это достаточно часто, что я обычно использую первый (что проще вводить, во всяком случае), хотя ls не является командой, которая жалуется, когда получает SIGPIPE.

Для диапазона строк:

ls -l | sed -n 2,4p

Для нескольких диапазонов строк:

ls -l | sed -n -e 2,4p -e 20,30p
ls -l | sed -n -e '2,4p;20,30p'
  • 0
    Что означает р? как 2р 3р? В том смысле, что я понимаю, что это для 2/3 строки, но какова теория / понимание этого?
  • 3
    @LeoUfimtsev: p - это оператор sed который печатает строки, идентифицируемые диапазоном предшествующих ему строк. Таким образом, 2,4p означает печать строк 2, 3, 4.
Показать ещё 1 комментарий
66
ls -l | head -2 | tail -1
  • 13
    +2, но я бы предложил head -n 2 | tail -n 1 - современные головы и хвосты имеют тенденцию выдавать предупреждения иначе.
  • 2
    Использование двух процессов для фильтрации данных немного излишне (но, учитывая мощь машин в наши дни, они, вероятно, справятся). Обобщение для обработки одного диапазона не совсем тривиально (для диапазона N..M вы используете head -n M | tail -n M-N+1 ), а обобщение для обработки нескольких диапазонов невозможно.
Показать ещё 5 комментариев
33

Альтернатива хорошему виду/хвосту:

ls -al | awk 'NR==2'

или

ls -al | sed -n '2p'
  • 1
    мой awk лучше, но sed это приятно.
  • 0
    Нет необходимости в «если» - см. Ответ хакера (за исключением части о поиске каждого файла в системе). ;-)
Показать ещё 5 комментариев
18

От sed1line:

# print line number 52
sed -n '52p'                 # method 1
sed '52!d'                   # method 2
sed '52q;d'                  # method 3, efficient on large files

От awk1line:

# print line number 52
awk 'NR==52'
awk 'NR==52 {print;exit}'          # more efficient on large files
  • 3
    exit отличный трюк для больших файлов
  • 5
    Upvote для добавления возможности останавливаться на больших файлах.
6

Для полноты; -)

более короткий код

find / | awk NR==3

более короткая жизнь

find / | awk 'NR==3 {print $0; exit}'
  • 0
    Ты не шутишь о полноте!
  • 0
    Я не ;-) На самом деле, я не знаю, почему все используют ls - первоначальный вопрос был о чьём-то STDOUT , поэтому я подумал, что лучше иметь его побольше.
Показать ещё 6 комментариев
6

Попробуйте эту версию sed:

ls -l | sed '2 ! d'

В нем говорится: "Удалите все строки, которые не являются вторыми".

5

Вы можете использовать awk:

ls -l | awk 'NR==2'

Update

Вышеприведенный код не получит того, чего мы хотим, из-за ошибки "один за другим": первая строка ls -l - это общая строка. Для этого будет работать следующий пересмотренный код:

ls -l | awk 'NR==3'
4

Доступен ли Perl для вас?

$ perl -n -e 'if ($. == 7) { print; exit(0); }'

Очевидно, замените любой номер, который вы хотите для 7.

  • 0
    Это мой фаворит, так как, кажется, его проще всего обобщить на то, чем я был лично, после которого каждый n-й, perl -n -e 'if ($.% 7 == 0) {print; Выход (0); }»
  • 0
    @matkelcey также вы можете сделать $ awk 'NR % 7' filename чтобы напечатать каждую седьмую строку в файле.
1

Другой плакат предложил

ls -l | head -2 | tail -1

но если вы заводите голову в хвост, все выглядит так, как будто все линии линии N обрабатываются дважды.

Трубопровод хвоста в голову

ls -l | tail -n +2 | head -n1

будет более эффективным?

  • 0
    хаха смешной хвост + голова. но помогите
0

Хм

sed не работал в моем случае. Я предлагаю:

для "нечетных" строк 1,3,5,7... ls | awk '0 == (NR + 1)% 2'

для "четных" строк 2,4,6,8 ls | awk '0 == (NR)% 2'

0

Да, самый эффективный способ (как уже указывал Джонатан Леффлер) - использовать sed с печатью и выйти:

set -o pipefail                        # cf. help set
time -p ls -l | sed -n -e '2{p;q;}'    # only print the second line & quit (on Mac OS X)
echo "$?: ${PIPESTATUS[*]}"            # cf. man bash | less -p 'PIPESTATUS'
  • 0
    Использование pipefail и PIPESTATUS очень интересно, и это многое добавляет на эту страницу.
-1

Для большей полноты.

ls -l | (for ((x=0;x<2;x++)) ; do read ; done ; head -n1)

Выбросьте строки, пока не дойдете до второго, затем распечатайте первую строку после этого. Таким образом, он печатает третью строку.

Если это только вторая строка.

ls -l | (read; head -n1)

Поместите столько "прочитанных как необходимо".

-2

Я добавил это в свой .bash_profile

function gdf(){
  DELETE_FILE_PATH=$(git log --diff-filter=D --summary | grep delete | grep $1 | awk '{print $4}')
  SHA=$(git log --all -- $DELETE_FILE_PATH | grep commit | head -n 1 | awk '{print $2}')
  git show $SHA -- $DELETE_FILE_PATH
}

И он работает

gdf <file name>

Ещё вопросы

Сообщество Overcoder
Наверх
Меню