gensub()
ожидает строку в качестве второго аргумента. Вы пытаетесь объединить /
и ,
вокруг выражения (\\1+3)
, которое, как вы предполагаете, будет оцениваться функцией. Я не буду. Он оценивается перед вызовом функции. Вы используете \1
для ссылки на соответствующую группу захвата ()
в регулярном выражении, но вы можете использовать ее только в строке, а не в выражении.
Таким образом, в лучшем случае вы можете использовать в качестве второго аргумента "/\\1+3,"
, но тогда вы получите результат ...Backslash/49+3,Black
. Вы не можете оценить часть 49+3 таким образом.
Если вы хотите выполнить арифметические действия с совпадением, вы должны сначала извлечь строку, выполнить арифметические действия, а затем поместить ее обратно в строку. Например,
awk '{ n = split($0, d, /\/([0-9]+),/, s)
print d[1] "/"(substr(s[1],2)+3)"," d[2] }'
Здесь используется функция split()
gnu awk с регулярным выражением для разделения строки на 3 части :часть до совпадения в d[1]
, часть после совпадения в d[2]
и совпавшая строка "/49,"
в с[1]. Вы действительно должны проверить, что n
равно 2, чтобы убедиться, что вы получили ровно одно совпадение.
Затем вы можете извлечь число из совпадающей строки, просто пропустив начальный "/"
, выполнить арифметические действия и снова соединить все части вместе.
Если шаблон может появляться несколько раз в одной строке ваших данных,лучшее решение — использовать match()
, чтобы найти только последнее вхождение, и разрезать строку, используяsubstr()
:
awk '{ match($0, /.*\/([0-9]+),/, m)
a = m[1,"start"]
b = m[1,"length"]
if(a)print substr($0,1,a-1) substr($0,a,b)+3 substr($0,a+b)
else print }'
Здесь шаблон .*
добавлен спереди, чтобы соответствовать только последнему вхождению. a
устанавливается на позицию символа начала группы захвата ()
в регулярном выражении, а b
— на ее длину, поэтому substr($0,a,b)
— это просто число. Последняя строка собирается из двух других частей исходных данных.
Функция оболочки, заменяющаяsponge
:
mysponge () (
append=false
while getopts 'a' opt; do
case $opt in
a) append=true ;;
*) echo error; exit 1
esac
done
shift "$(( OPTIND - 1 ))"
outfile=$1
tmpfile=$(mktemp "$(dirname "$outfile")/tmp-sponge.XXXXXXXX") &&
cat >"$tmpfile" &&
if "$append"; then
cat "$tmpfile" >>"$outfile"
else
if [ -f "$outfile" ]; then
chmod --reference="$outfile" "$tmpfile"
fi
if [ -f "$outfile" ]; then
mv "$tmpfile" "$outfile"
elif [ -n "$outfile" ] && [ ! -e "$outfile" ]; then
cat "$tmpfile" >"$outfile"
else
cat "$tmpfile"
fi
fi &&
rm -f "$tmpfile"
)
Эта mysponge
функция оболочки передает все данные, доступные для стандартного ввода, во временный файл.
Когда все данные перенаправлены во временный файл, собранные данные копируются в файл, указанный в аргументе функции. Если данные не должны добавляться к файлу (, т.е. -a
не используется ), и если заданное имя выходного файла относится к существующему обычному файлу, если он не существует, то это делается с помощьюmv
(в случае, если файл является существующим обычным файлом, делается попытка передать режимы файла во временный файл с помощью GNU chmod
сначала ). Если вывод не является обычным файлом (, именованным каналом, стандартным выводом и т. д. ), данные выводятся с помощью cat
.
Если в командной строке не указан файл, собранные данные отправляются на стандартный вывод.
В конце временный файл удаляется.
Каждый шаг в функции зависит от успешного завершения предыдущего шага.Попытки удалить временный файл не предпринимаются, если одна команда не удалась (, он может содержать важные данные ).
Если именованный файл не существует, то он будет создан с правами пользователя по умолчанию и т. д., и в него будут записаны данные, поступающие со стандартного ввода.
Утилита mktemp
не является стандартной, но общедоступной.
Приведенная выше функция имитирует поведение, описанное в руководстве дляsponge
из пакета moreutils
в Debian.
Использование tee
вместо sponge
нецелесообразно. Вы говорите, что пробовали это, и вам показалось, что это сработало. Это может работать, а может и нет. Это зависит от времени запуска команд в конвейере (, они запускаются практически одновременно ), а также от размера файла входных данных.
Ниже приведен пример, показывающий ситуацию, когда использование tee
не работает.
Исходный файл имеет размер 200 000 байт, но после конвейера он усекается до 32 КиБ (, что вполне может соответствовать некоторому размеру буфера в моей системе ).
$ yes | head -n 100000 >hello
$ ls -l hello
-rw-r--r-- 1 kk wheel 200000 Jan 10 09:45 hello
$ cat hello | tee hello >/dev/null
$ ls -l hello
-rw-r--r-- 1 kk wheel 32768 Jan 10 09:46 hello
Вот такой короткий bash-скрипт, для которого требуется Perl
https://github.com/ildar-shaimordanov/perl-utils#sponge
Второй скрипт должен быть дропом -взамен версии в moreutils
Существует также версия, которая представляет собой отдельный -perl-скрипт.
function wf() {
#create a temporary file
local tmpf="${1}_$(< /dev/urandom tr -dc A-Za-z0-9 | head -c16)"
#redirect the result
cat > $tmpf
#replace the original file
mv -f $tmpf "${1}"
}
Далее мы используем функцию
grep "error" messages.log | wf messages.log