awk -- заменить один раз после немедленного шаблона в той же строке!

Вы можете установить прокси в настройках, и он будет отображаться везде

enter image description here

1
07.02.2020, 11:24
3 ответа

Хотя теоретически возможно написать регулярное выражение, которое соответствует самой короткой строке, не соответствующей «false», это сложно. Различные другие языки имеют синтаксис для выбора кратчайшего пути, но awk не входит в их число.

Таким образом, есть 3 подхода, которые можно использовать, предполагая, что вы не хотите писать сложное выражение.

  1. Вы можете разделить ввод на слово "false", перебрать поля в цикле, если текущее поле соответствует шаблону, то распечатать его, а затем "true", в противном случае распечатать его, а затем "false".
  2. Вы можете использовать хитрость, преобразовать все вхождения "false" в один неиспользуемый символ, такой как элемент управления -a, тогда регулярное выражение будет легко написать, как вы можете сказать [^\001] *\001 чтобы соответствовать кратчайшему шаблону, заканчивающемуся элементом управления -a.
  3. Вы просто перебираете поля,если текущее поле является вашим шаблоном, вы устанавливаете флаг, если оно «ложно» и флаг установлен, вы меняете его на «истина» и сбрасываете флаг.

Для подхода № 3.

#!/usr/bin/awk

/PATTERN.*false/ {
        for(i=1;i<=NF;i++) {
                if ($i ~ /PATTERN/) flag=1;
                if ($i == "false" && flag==1) {
                        $i="true"
                        flag=0
                }
        }
}
{print}

Это приведет к сворачиванию пробелов во входных данных.

1
28.04.2021, 23:24

Это решение реализует подход к разделению строки в PATTERN(split), замене первой falseна вторую часть(sub)и объединению частей(forloop иprintf). Команда nextпропускает дальнейшую обработку этой входной строки. Остальные строки печатаются без изменений.(1— всегда верное условие с действием по умолчанию.)

awk '/PATTERN.*false/ {
    n=split($0,parts,"PATTERN"); 
    sub("false", "true", parts[2]); 
    for(i=1;i<n;i++) {
        printf("%s%s", parts[i], "PATTERN");
    }
    printf("%s\n", parts[n]);
    next }
1'

Из вопроса неясно, всегда ли значение, соответствующее PATTERN, равно false, поэтому оно может заменить неправильное false.

Пример ввода

colorA is false colorB is false PATTERN is false colorC is false colorD is false
colorA is false colorB is false PATTERN is true colorC is false colorD is false

приводит к этому результату

colorA is false colorB is false PATTERN is true colorC is false colorD is false
colorA is false colorB is false PATTERN is true colorC is true colorD is false

Отредактируйте в соответствии с комментарием RudiC :Если to -будет -измененным значением после PATTERN либо "true", либо "false", то эта возможная проблема можно избежать, заменив инструкцию sub("false", "true", parts[2]);наsub("false|true", "true", parts[2]);

awk '/PATTERN.*false/ {
    n=split($0,parts,"PATTERN"); 
    sub("false|true", "true", parts[2]); 
    for(i=1;i<n;i++) {
        printf("%s%s", parts[i], "PATTERN");
    }
    printf("%s\n", parts[n]);
    next }
1'

При том же входном образце это приводит к

colorA is false colorB is false PATTERN is true colorC is false colorD is false
colorA is false colorB is false PATTERN is true colorC is false colorD is false
0
28.04.2021, 23:24

С GNU awk для соответствия третьего аргумента ()и gensub():

$ awk 'match($0,/(.*PATTERN)(.*)/,a){$0=a[1] gensub(/false/,"true",1,a[2])} 1' file
...
colorA is false colorB is false PATTERN is true colorC is false colorD is false
...

и с любым awk:

$ awk 'match($0,/.*PATTERN/){tail=substr($0,RSTART+RLENGTH); sub(/false/,"true",tail); $0=substr($0,1,RSTART+RLENGTH-1) tail } 1' file
...
colorA is false colorB is false PATTERN is true colorC is false colorD is false
...
0
28.04.2021, 23:24

Теги

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