скрипт оболочки linux для удаления 1 символа в определенном поле в файле, содержащем строки длиной около 3000

Вопрос или проблема

  • Мой входной файл:
    1oo+457864227yexaloo+6784536pkp8907654
    2oo+499004227yexaloo+69008908pkp8907654
    3oo+648968976yexaloo+53589094pkp8907654
    4oo+490764578yexaloo+6784536pkp8907654
    

Я хочу выяснить длину цифр между вторым появлением oo+ и pkp. Если длина больше 7 цифр, я хочу убрать первый символ o в oo только у второго появления.

  • Желаемый выходной файл
    1oo:457864227yexaloo:6784536pkp8907654
    2oo:499004227yexalo:69008908pkp8907654
    3oo:648968976yexalo:53589094pkp8907654
    4oo:490764578yexaloo:6784536pkp8907654
    

Может кто-то помочь, как этого добиться?

Этот однострочник Perl найдет второе появление oo+ и затем захватит самую длинную строку цифр после этого до первого pkp. Обратите внимание, что он предполагает только цифры между вторым oo+ и pkp. Затем, в зависимости от длины диапазона цифр, он выведет либо o+, либо oo+. То, что, по-видимому, спрашивается в вашем вопросе:

$ perl -nle '/(.*oo\+.*?)oo\+((\d+)pkp.*)/; 
             print length($3) > 7 ? "${1}o+$2" : "${1}oo+$2"' файл
1oo+457864227yexaloo+6784536pkp8907654
2oo+499004227yexalo+69008908pkp8907654
3oo+648968976yexalo+53589094pkp8907654
4oo+490764578yexaloo+6784536pkp8907654

Однако вывод, который вы показываете, на самом деле не соответствует тому, что описывает ваш вопрос. Вы также изменили + после каждого из двух oo на :. Если это также нужно, попробуйте

$ perl -nle 's/oo\+/oo:/g; /(.*oo:.*?)oo:((\d+)pkp.*)/; 
             print length($3) > 7 ? "${1}o:$2" : "${1}oo:$2"' файл
1oo:457864227yexaloo:6784536pkp8907654
2oo:499004227yexalo:69008908pkp8907654
3oo:648968976yexalo:53589094pkp8907654
4oo:490764578yexaloo:6784536pkp8907654

Объяснение

  • perl -nle : Флаг -n говорит Perl открыть входной файл и затем применить скрипт, указанный с помощью -e, к каждой строке. Флаг -l убирает завершающие новые строки из ввода и добавляет новую строку к каждому вызову print.
  • s/oo\+/oo:/g;: заменяет все вхождения oo+ на oo:.
  • /(.*oo:.*?)oo:((\d+)pkp.*)/;: скобки – это “группы захвата”; все, что соответствует одному из шаблонов в скобках, будет доступно как $N, при этом первая захваченная группа будет $1, вторая – $2 и так далее. Здесь $1 будет все до второго oo: (не oo+, потому что мы заменили + на : на предыдущем этапе), $2 будет все после второго oo: до конца строки, а $3 будет числа, которые вы ищете (так как скобки вложенные, это работает как (внешняя скобка - это $2 (внутренняя - $3))).
  • print length($3) > 7 ? "${1}o:$2" : "${1}oo:$2" : это сокращенная форма, которую можно записать как “если длина $3 (числа) больше 7, напечатать $1, затем o, затем : и $2; если длина меньше 7, напечатать $1, затем oo, затем : и $2. Общий синтаксис команда теста ? случай1 : случай2, который читается как если(тест){ команда случай1} иначе{ команда случай2 }.

Это на самом деле немного сложнее, чем я думал. Это предполагает, что файл называется strings.txt.

#!/bin/bash

# Читаем strings.txt в массив
mapfile -t strings_file < strings.txt

# Итерация и извлечение номеров
for string in "${strings_file[@]}"; do
    number_extract=$(echo "$string" | sed -n 's/.*oo+.*oo+\(.*\)pkp.*/\1/p')

    count_digits=${#number_extract}

    # Проверяем, если длина больше 7
    if [ "$count_digits" -gt 7 ]; then
        string=$(echo "$string" | sed 's/oo/o/2')
    fi

    # Заменяем + на :
    string=$(echo "$string" | sed 's/+/:/g')

    echo "$string" >> string_output.txt
done

exit 0

Сохраните как: char_edit.sh
Сделайте исполняемым: chmod +x char_edit.sh
Запустите с помощью: ./char_edit.sh

Это довольно просто с помощью awk:

$ awk '{match($0,/oo\+[[:digit:]]+pkp/); if (RLENGTH>13) {$0=gensub(/oo\+/,"o+",2)}}1' input.txt 

1oo+457864227yexaloo+6784536pkp8907654
2oo+499004227yexalo+69008908pkp8907654
3oo+648968976yexalo+53589094pkp8907654
4oo+490764578yexaloo+6784536pkp8907654

Это применит функцию match() для поиска шаблона “oo+, за которым следует любое количество цифр, за которыми следует pkp“.

  • Если найдено, RLENGTH, длина совпадения (количество цифр + длина oo+ + длина pkp), проверяется, превышает ли она 13 (7+3+3). Если да, то функция gensub() используется для замены второго совпадения oo+ на o+ в текущей строке ($0).
  • Кажется, что одиночный 1 выведет текущую строку, включая любые изменения.

Если вы действительно хотите дополнительно изменить o+ на o:, вам нужно изменить программу следующим образом:

$ awk '{match($0,/oo\+[[:digit:]]+pkp/); if (RLENGTH>13) {$0=gensub(/oo\+/,"o+",2)}; gsub(/o\+/,"o:")}1' input.txt 

1oo:457864227yexaloo:6784536pkp8907654
2oo:499004227yexalo:69008908pkp8907654
3oo:648968976yexalo:53589094pkp8907654
4oo:490764578yexaloo:6784536pkp8907654

Ответ или решение

Чтобы решить задачу по редактированию строк в файле с использованием скрипта на bash, можно воспользоваться различными утилитами командной строки Linux, такими как awk, sed и bash. В этой инструкции будет представлен подробный скрипт, который удовлетворяет вашим требованиям. Ниже описан пошаговый подход к его созданию и применению.

Исходные данные

Исходный файл (input.txt):

1oo+457864227yexaloo+6784536pkp8907654
2oo+499004227yexaloo+69008908pkp8907654
3oo+648968976yexaloo+53589094pkp8907654
4oo+490764578yexaloo+6784536pkp8907654

Цель

  1. Найти длину строки из только чисел между второйoccurrence oo+ и pkp.
  2. Если длина чисел превышает 7 символов, заменить вторую oo+ на o+.
  3. Заменить все + на :.

Скрипт

Ниже приведен пример bash-скрипта для достижения поставленных задач. Скрипт сначала считывает файл, затем обрабатывает каждую строк по условию и сохраняет результат в новый файл.

#!/bin/bash

# Имя входного файла
input_file="input.txt"
# Имя выходного файла
output_file="output.txt"

# Открываем выходной файл для записи
> "$output_file"

# Обработка каждой строки
while IFS= read -r line; do
    # Ищем все вхождения `oo+`
    occurrences=($(echo "$line" | grep -o 'oo+'))

    # Проверяем, найдены ли ровно два вхождения
    if [ "${#occurrences[@]}" -ge 2 ]; then
        # Извлекаем часть строки между вторым `oo+` и `pkp`
        second_occurrence_index=$((${#occurrences[@]} - 1))
        digits_part=$(echo "$line" | sed -n "s/.*oo+.*oo+\([0-9]*\)pkp.*/\1/p")

        # Подсчитываем длину
        count_digits=${#digits_part}

        # Если длина превышает 7, то заменяем `oo+` на `o+`
        if [ "$count_digits" -gt 7 ]; then
            line=$(echo "$line" | sed 's/oo\+/o+/2')
        fi
    fi

    # Заменяем все `+` на `:`
    line=$(echo "$line" | sed 's/+/:/g')

    # Записываем строку в выходной файл
    echo "$line" >> "$output_file"
done < "$input_file"

Как использовать скрипт

  1. Создайте файл, например char_edit.sh, и скопируйте в него указанный скрипт.
  2. Убедитесь, что у вас есть разрешения на выполнение: выполните команду:
    chmod +x char_edit.sh
  3. Запустите скрипт:
    ./char_edit.sh

Описание работы скрипта

  • Чтение файла: Входные данные считываются построчно.
  • Поиск вхождений oo+: В каждой строке скрипт находит все вхождения oo+ и фиксирует их.
  • Обработка длины строки: Отсюда, с помощью sed, извлекается часть с цифрами между второй oo+ и pkp, и определяется её длина.
  • Заменить oo+ на o+: Если длина цифр превышает 7, выполняется замена второго вхождения oo+ на o+.
  • Замена + на :: После этого все вхождения символа + заменяются на :.
  • Запись результата: Обработанные строки записываются в выходной файл.

Заключение

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

Оцените материал
Добавить комментарий

Капча загружается...