Сценарий, соответствующий литеральному шаблону по нескольким строкам?

Какова Ваша версия CUPS и распределения? С тех пор 1.4.x, CUPS может использовать libusb говорить с узлами USB-устройства вместо прохождения через lpusb.

3
07.12.2012, 00:55
3 ответа

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

Следующий сценарий только использует оболочку встроенные функции и cat. Это должно работать над оболочкой Android, по крайней мере, начиная с Имбирного пряника и определенно начиная с 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

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

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

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"
2
27.01.2020, 21:14
  • 1
    Вы так правы относительно невозможного distinguishment. Я совершил реальную ошибку. Черт возьми Ваш ответ является большим! Большое спасибо. –  Sepero 07.12.2012, 19:40
  • 2
    Разве не было бы более безопасно поймать новые строки с помощью этого? случай "$contents" в –  Sepero 07.12.2012, 19:43
  • 3
    @Sepero Вы имеете в виду case "$contents" in вместо case $contents in? Это - один из нескольких случаев, где можно не учесть двойные кавычки. Может только быть отдельное слово, таким образом, оболочка не делает разделения слова и globbing даже без двойных кавычек. Можно также не учесть двойные кавычки в присвоениях: foo=$bar эквивалентно foo="$bar". Однако export foo=$bar не безопасно: если bar hello world, это работает export foo=hello world, т.е. набор foo кому: hello и экспортируйте обоих foo и world). Если Вы не хотите запоминать такие исключения, используйте двойные кавычки все время. –  Gilles 'SO- stop being evil' 07.12.2012, 19:50

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

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

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

Во-первых, создайте f2 файл:

cat << EOF > f2
$PAT
EOF

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

diff $FILE f2 > diff_res
res=$?

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

Если diff_res содержит строку, запускающуюся">", f2 содержит по крайней мере одну строку не в $FILE. Протестировать это:

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

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

  • Одна строка, не запускающаяся с"<"(если f1 или f3 пусты),
  • Две строки, не запускающиеся с"<", 1-е всегда запуск с"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 является различным результатом только со строками, запускающимися"<"без тех 2 символ:

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
3
27.01.2020, 21:14
  • 1
    я должен был выбрать ответ Gilles для простоты, но это было просто блестящим! Превосходный материал. –  Sepero 07.12.2012, 19:35

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

1
27.01.2020, 21:14

Теги

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