Вопрос или проблема
- Мой входной файл:
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
Цель
- Найти длину строки из только чисел между второйoccurrence
oo+
иpkp
. - Если длина чисел превышает 7 символов, заменить вторую
oo+
наo+
. - Заменить все
+
на:
.
Скрипт
Ниже приведен пример 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"
Как использовать скрипт
- Создайте файл, например
char_edit.sh
, и скопируйте в него указанный скрипт. - Убедитесь, что у вас есть разрешения на выполнение: выполните команду:
chmod +x char_edit.sh
- Запустите скрипт:
./char_edit.sh
Описание работы скрипта
- Чтение файла: Входные данные считываются построчно.
- Поиск вхождений
oo+
: В каждой строке скрипт находит все вхожденияoo+
и фиксирует их. - Обработка длины строки: Отсюда, с помощью
sed
, извлекается часть с цифрами между второйoo+
иpkp
, и определяется её длина. - Заменить
oo+
наo+
: Если длина цифр превышает 7, выполняется замена второго вхожденияoo+
наo+
. - Замена
+
на:
: После этого все вхождения символа+
заменяются на:
. - Запись результата: Обработанные строки записываются в выходной файл.
Заключение
Скрипт, который был представлен, удобен, эффективен и легко адаптируется под дополнительные требования. С его помощью вы сможете оперативно обрабатывать массив данных и применять нужные изменения к строкам в вашем файле.