Скрипт сопоставляет буквенный шаблон по нескольким строкам?

У меня есть многострочная строка в переменной $PAT . $PAT необходимо искать в файле $FILE . Если $PAT находится в $FILE , ему необходимо распечатать файл с удаленным $PAT . Если $PAT не найден, то ничего не печатайте. Неизвестно, если $PAT содержит любые специальные символы, и он должен соответствовать буквально. Например, если $PAT является //\/\\|* то эту точную 8-символьную строку нужно искать в $FILE .

Для этого используется реальный мир для установки и удаления текста в уже существующих файлах / сценариях. Если вы хотите добавить $PAT в $FILE , вы хотите знать, было ли оно уже добавлено ранее. Если $PAT уже находится в $FILE , то выход без $PAT позволяет вам легко удалить его.

Для систем, для которых мне нужен такой скрипт (для устройств Android), есть только BusyBox. Нет Perl или других языков сценариев.

3 Solutions collect form web for “Скрипт сопоставляет буквенный шаблон по нескольким строкам?”

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

Следующий скрипт использует только встроенные функции оболочки и cat . Он должен работать на оболочке Android, по крайней мере, с Gingerbread и определенно с Ice Cream Sandwich. Он печатает содержимое файла минус первое вхождение $PAT если оно есть; если $PAT не встречается, он ничего не печатает.

 contents=$(cat "$FILE") case $contents in *"$PAT"*) echo "${contents%%$PAT*}${contents#*$PAT}";; esac 

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

 contents=$(cat "$FILE"; echo a) contents=${contents%a} case $contents in *"$PAT"*) contents="${contents%%$PAT*}${contents#*$PAT}" dashes=${contents%%[!-]*} echo -n "$dashes" echo -n "${contents#$dashes}";; esac 

(Обратите внимание, что предлагаемое поведение не позволяет отличить файл, содержащий именно шаблон и пустой файл.)

На самом деле проще реализовать скрипт append / remove напрямую, чем использовать предлагаемую промежуточную функцию.

 contents=$(cat "$FILE"; echo a) contents=${contents%a} append= case $contents in *"$PAT"*) contents="${contents%%$PAT*}${contents#*$PAT}";; *) contents="$contents$PAT" esac dashes=${contents%%[!-]*} { echo -n "$dashes"; echo -n "${contents#$dashes}"; } >"$FILE.new" mv -- "$FILE.new" "$FILE" 

Если вы хотите сопоставить $PAT как полные строки, у меня есть решение. По завершающим строкам я имею в виду, что в случае совпадения вы можете разделить $FILE на три подфайла (f1, f2 и f3), где:

  • cat f1 f2 f3$FILE ,
  • f2 – $PAT .

Заметим, что f1 и / или f3 могут быть пустыми.

Сначала создайте файл f2:

 cat << EOF > f2 $PAT EOF 

Затем, diff $ FILE и f2, сохраняя результат:

 diff $FILE f2 > diff_res res=$? 

Если $res равно нулю, то f1 и f3 пусты, а $ FILE равно $ PAT. Я предполагаю, что вы хотите получить пустой файл в этом случае.

Если diff_res содержит строку, начинающуюся с " > ", f2 содержит хотя бы одну строку, не diff_res в $ FILE. Чтобы проверить это:

 grep -q '^> ' diff_res test $? -eq 0 && echo "PAT not found" 

Если diff_res не содержит строк, начинающихся с « > », все строки из f2 находятся в $ FILE, но, возможно, не смежно. Если это смежно, diff_res будет содержать:

  • Одна строка, не начинающаяся с « < » (если f1 или f3 пусты),
  • Две строки не начинаются с « < », первый всегда начинается с « 1d » или «1».

Чтобы проверить это, мы имеем:

 nb=$(grep -v "^< " diff_res | wc -l) if test $nb -gt 2; then pat_found=0 elif test $nb -eq 1; then pat_found=1 else pat_found=$(sed -n -e '1{/^1d/p;/^1,/p}' diff_res | wc -l) fi 

Затем, если pat_found равен 1, файл без $ PAT является результатом diff с только строками, начинающимися с « < » без этих двух символов:

 grep '^< ' diff_res | cut -c 3- 

Полный и реорганизованный сценарий будет выглядеть так:

 # Output the desired result on stdin. f2=/tmp/f2 # Use of PID or mktmp would be better' diff_res=/tmp/diff_res # Use of PID or mktmp would be better' cat << EOF > $f2 $PAT EOF diff $FILE $f2 > $diff_res if test $? -ne 0; then grep -q '^> ' $diff_res if test $? -ne 0; then nb=$(grep -v "^< " $diff_res | wc -l) if test $nb -eq 1; then grep '^< ' $diff_res | cut -c 3- elif test $nb -eq 2; then pat_found=$(sed -n -e '1{/^1d/p;/^1,/p}' $diff_res | wc -l) test $pat_found -eq 1 && grep '^< ' $diff_res | cut -c 3- fi fi fi rm -f $f2 $diff_res 

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

  • Монетный двор Linux: сделать «общедоступную интерактивную пусковую установку» только из корня sh?
  • Выполните эскиз строк сценария перед их запуском
  • Как «захватить» соответствующие файлы из файла поиска в bash?
  • я хочу напечатать строку, которая начинается с словесного слова, а в остальных записях печатается только одно поле
  • Как получить дату с двухнедельной давности с использованием даты Solaris?
  • Проверка и проверка блокировки из другого процесса
  • Как получится, когда x = abc, ] && echo yes || эхо не возвращается?
  • Постоянная история Баша между отдельными процессами
  • Bash CD до тех пор, пока в определенной папке
  • Можно ли отслеживать отправленные письма?
  • Как узнать, печатает ли программа на stderr или stdout в терминале?
  • Linux и Unix - лучшая ОС в мире.