Для заданного ввода выполните поиск в файле .txt, и, если поиск найден, выведите всю строку

Вот еще один способ сделать это, очень похожий на ответ подстановочный знак :

files=( file1.csv file2.csv)
eval paste "<( cut -d, -f1 ${^files[@]} )"

Вместо для , здесь используется расширение $ {^ ...} , специфичное для Zsh.

Причина, по которой файлы должны быть назначены первыми, заключается в том, что подстановка всегда выполняется в последнюю очередь, поэтому, если файлы необходимо сгенерировать автоматически (как в files = (* .csv ) ) то что-то вроде $ {^ :-( * .csv)} будет расширяться только после того, как будут выполнены все остальные расширения. Мы хотим, чтобы он сначала расширил .

Расширение $ {^ ...} заставляет результирующий массив действовать как результат раскрытия фигурных скобок. Например, назначьте x = (a b) , а затем сравните echo $ {x} y с echo $ {^ x} y .

Цитирование необходимо для того, чтобы Zsh трактовал окружающий текст как буквальную строку. В противном случае он разделит командную строку на пробелы, поэтому наше $ {^ ...} расширение сократится до "" $ {^ ...} "" ; то есть каждый элемент будет окружен только пустой строкой. То есть

echo "<( cut -d, -f1 ${^files[@]} )"

и

echo "<( cut -d, -f1 "\
${^files[@]}\
" )"

эквивалентны, но не то же самое, что

echo <( cut -d, -f1 ${^files[@]} )

. Но использование кавычек создает новую проблему: командная строка анализируется и разделяется без учета происходящего раскрытия. То есть, даже несмотря на то, что мы фактически ввели

paste <( cut -d, -f1 file1.csv ) <( cut -d, -f1 file2.csv )

по желанию, это фактически анализируется как

paste '<( cut -d, -f1 file1.csv )' '<( cut -d, -f1 file2.csv )'

Следовательно, нам нужно eval , чтобы повторно проанализировать правильно сформированное выражение. Чтобы увидеть это в действии, сравните

setopt noxtrace
eval paste "<( cut -d, -f1 ${^files[@]} )" 1>/dev/null 2>&1

с

setopt xtrace
eval paste "<( cut -d, -f1 ${^files[@]} )" 1>/dev/null 2>&1

. Я надеялся, что какая-то комбинация вложенных расширений, $ {...: - ...} , а флаги раскрытия параметров Q , z и / или s приведут к переоценке без eval , но, очевидно, это не так. Я также хотел бы, чтобы был способ принудительно использовать глобусы, но опять же это кажется невозможным.

0
28.04.2018, 18:00
4 ответа

Для этого можно использовать grep:

grep 56896 file.txt

Если вы хотите написать сценарий, это может быть что-то вроде этого:

#!/bin/bash

inputfile='/path/to/file.txt'

grep "$1" "$inputfile"

Который вы затем запустите как:

$./script.sh 56896
0
28.01.2020, 04:24

Что-то вроде

grep BOOKNUMBER textfile.txt

должен решить эту проблему.

Если вы хотите, чтобы при поиске книги номер 96 также не было списка «Состояние Тома Тэтчера», вы можете использовать

grep '[[:space:]]BOOKNUMBER[[:space:]]*$' textfile.txt

вместо этого.


Как скрипт (сохранить какsearchbook)

#!/bin/bash

BOOKFILE=/path/to/bookfile.txt

BOOK=$1
if [[ -z "$BOOK" ]]; then 
    echo -n "Booknumber? "
    read BOOK
fi

grep '[[:space:]]'$BOOK'[[:space:]]*$' $BOOKFILE

Затем вы можете запустить

searchbook BOOKNUMBER

или

searchbook

Во втором случае вам будет предложено ввести номер.

0
28.01.2020, 04:24

Чтобы напечатать строки, для которых последнее слово является чем-то, на ум приходит awk:

awk '$NF == "123"' # string comparison
awk '$NF == 123'   # number comparison, would also match on 0123, 123.0, 1.23e2
awk '$NF == ENVIRON["ENVVAR"]' # number comparison if both $NF and $ENVVAR
                               # look like numbers, string otherwise

Для awkэти слова по умолчанию разделены пробелами -. В зависимости от реализации пробел может быть только символом пробела или табуляции, некоторые из них могут включать другие пробелы Unicode, если они классифицируются как таковые в локали. Реализацияbusyboxawkтакже включает символы вертикального интервала, включая символ возврата каретки.

Если ваш файл отформатирован с использованием разделителей строк MS -DOS, то есть последовательности символов CR LF, а не просто LF, то описанное выше не будет работать, кроме как с busybox awk. И даже с busybox awk в строках вывода по-прежнему будут те проблемные управляющие символы, которых не должно быть в Unix.

Таким образом, вы должны предварительно обработать ввод с помощью dos2unixили d2u, чтобы преобразовать окончания строк в формат Unix.

< file.dos dos2unix | awk '$NF == 123'

Ваш входной файл выглядит так, как будто он состоит из записей, разделенных пустыми строками. Если вы хотите напечатать полные записи для номера книги, вы можете сделать:

export BOOKNUMBER=123
< file.dos dos2unix | awk -v RS= -F '\n' '
    field[split($1, field, " ")] == ENVIRON["BOOKNUMBER"]'

Там мы устанавливаем разделитель записей на пустую строку для входа в режим абзаца(записи, разделенные пустыми строками ), и разделитель полей на новую строку (, также известную как LF ), поэтому первая строка каждой записи находится в$1(первом поле ). Мы разделяем эту первую строку специальным разделителем полей " ", который по умолчанию является словом , разбивающимся на массив field.А затем сравнение последнего элемента этого массива(split()возвращает количество элементов, поэтому field[split()]— это последний элемент )с содержимым переменной окружения $BOOKNUMBER.

0
28.01.2020, 04:24

Чтобы не зацепить книгу#196вместе с книгой #96, я предлагаю аналогичное, но более краткое использованиеgrep:

grep ' 96$' file.txt

Символ $в регулярных выражениях означает «конец образца текста», поэтому он будет совпадать только в правильной строке.

Это также можно поместить в скрипт:

#!/bin/bash

grep " ${1}\$" /path/to/file.txt

Это также можно сделать более безопасно сawk:

awk -v book=96 '$NF == book {print}' file.txt
0
28.01.2020, 04:24

Теги

Похожие вопросы