Есть ли стандартная альтернатива губке для передачи файла в себя?

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)— это просто число. Последняя строка собирается из двух других частей исходных данных.

1
25.09.2019, 01:45
3 ответа

Функция оболочки, заменяющая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
6
27.01.2020, 23:40

Вот такой короткий bash-скрипт, для которого требуется Perl
https://github.com/ildar-shaimordanov/perl-utils#sponge

Второй скрипт должен быть дропом -взамен версии в moreutils

Существует также версия, которая представляет собой отдельный -perl-скрипт.

0
27.01.2020, 23:40
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
0
27.01.2020, 23:40

Теги

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