Вопрос или проблема
У меня есть файл, содержащий значения, которые нужно скрыть (заменить на XX), но они не всегда находятся на одном и том же месте в строке, и я не знаю их содержимого. Однако я знаю их расположение относительно конкретного совпадения.
Например, я хочу, чтобы третье и четвертое числа после “00 00” были заменены на XX
Оригинал:
AA BB CC 00 00 01 02 03 04 05 06 07
AA BB CC DD EE FF 00 00 08 09 10 11 12 13 14
Желаемый вывод:
AA BB CC 00 00 01 02 XX XX 05 06 07
AA BB CC DD EE FF 00 00 08 09 XX XX 12 13 14
Я пробовал использовать awk, но мне удалось только установить позицию относительно начала строки. Есть ли способ индексации $2 и $3 относительно конкретного совпадения, например?
Правка: в строке может быть только одно совпадение 00 00
, она не может содержать 00 00 00
, не нужно беспокоиться о ведущем или завершающем совпадении.
Моя (стыдная) попытка на данный момент была следующей:
cat file | awk -F'00 00' '{print $2}' | awk '{gsub ($3,"XX",$0);gsub ($4,"XX",$0)}1'
Помимо множества awk, я также теряю начало строк, так как все, что перед совпадением, отбрасывается моим первым awk
С использованием sed
или perl
это проще, чем с awk
, если у вас нет awk
, который поддерживает расширение gawk
‘s gensub()
:
sed 's/\(00 00 .. .. \).. ../\1XX XX/' < file
perl -pe 's/00 00 .. .. \K.. ../XX XX/' < file
gawk '{print gensub(/(00 00 .. .. ).. ../, "\\1XX XX", 1)}' < file
С POSIX awk
можно сделать так:
awk '
match($0, /00 00 .. .. .. ../) {
$0 = substr($0, 1, RSTART+11) "XX XX" substr($0, RSTART+RLENGTH)
}
{print}' < file
Вот один из подходов с использованием awk:
$ awk '
{
for(i=1; i<=NF; i++){
if($i=="00" && $(i+1)=="00"){
$(i+4)=$(i+5)="XX"
}
}
}1' file
AA BB CC 00 00 01 02 XX XX 05 06 07
AA BB CC DD EE FF 00 00 08 09 XX XX 12 13 14
Идея заключается в том, чтобы пройти по всем полям (for(i=1; i<=NF; i++)
; NF
– это количество полей) и искать случаи, когда текущее поле ($i
) и следующее ($(i+1)
) установлены в строку 00
. Затем мы меняем 3-е и 4-е поля на XX
($(i+4)=$(i+5)="XX"
; используя +4
и +5
, поскольку я считаю от первого 00
, а не от второго). Наконец, мы выводим всё. Действие по умолчанию для awk
, когда выражение оценивается как истинное, – это вывести строку, поэтому простое 1
, которое всегда истинно, часто используется как сокращение для print
.
Обратите внимание, что это имеет недостаток замены вашего разделителя полей на пробел. В этом примере это, похоже, не проблема, но если это так, просто укажите разделители ввода и вывода. Так что если ваш ввод содержит запятые, которые вы хотите сохранить, вам следует сделать так:
$ cat file
AA,BB,CC,00,00,01,02,03,04,05,06,07
AA,BB,CC,DD,EE,FF,00,00,08,09,10,11,12,13,14
$ awk -F',' -v OFS=',' '
{
for(i=1; i<=NF; i++){
if($i=="00" && $(i+1)=="00"){
$(i+4)=$(i+5)="XX"
}
}
}1' file
AA,BB,CC,00,00,01,02,XX,XX,05,06,07
AA,BB,CC,DD,EE,FF,00,00,08,09,XX,XX,12,13,14
Вы также можете просто рассматривать это как простую замену и сделать что-то вроде:
$ sed -E 's/( 00 00 .. ..) .. ../\1 XX XX/' file
AA BB CC 00 00 01 02 XX XX 05 06 07
AA BB CC DD EE FF 00 00 08 09 XX XX 12 13 14
Или
$ perl -pe 's/( 00 00 .. ..) .. ../$1 XX XX/' file
AA BB CC 00 00 01 02 XX XX 05 06 07
AA BB CC DD EE FF 00 00 08 09 XX XX 12 13 14
Используя awk
:
$ awk '
match($0, /00 00 [0-9]+ [0-9]+/)
{
printf substr($0,1,RSTART+RLENGTH)
$0=substr($0,RSTART+RLENGTH+1);
sub(/^[0-9]+ [0-9]+/, "XX XX")
}1' file
При условии, что только числа повторяются после 00 00
.
Ответ или решение
Чтобы заменить символы после конкретного совпадения с учетом сдвига, как в вашем вопросе, можно использовать несколько различных инструментов, таких как awk
, sed
или perl
. Давайте проанализируем каждое из этих решений и выберем наиболее подходящее.
Проблема
Вы хотите заменить третий и четвертый числа после строки "00 00" на "XX", и делаете это в текстовом файле с множеством строк. Важно, чтобы значение "00 00" встречалось в каждой строке только один раз, и нам нужно сохранить все остальные значения и структуру строки.
Решения
1. Использование awk
awk
— мощный инструмент для обработки текстовых данных. Вот один из возможных способов:
awk '{
for(i=1; i<=NF; i++){
if($i=="00" && $(i+1)=="00"){
$(i+4)=$(i+5)="XX"
}
}
} 1' ваш_файл.txt
Объяснение:
- Мы проходим по всем полям (
NF
— количество полей в строке). - Если текущее поле равно "00", а следующее тоже "00", мы заменяем третье и четвертое числа после "00 00" на "XX".
1
в конце является сокращением для командыprint
, что позволяет вывести измененную строку.
2. Использование sed
sed
— идеальный инструмент для простых подстановок на основе регулярных выражений. Вот пример команды:
sed -E 's/(00 00 [0-9]+ [0-9]+) [0-9]+ [0-9]+/\1 XX XX/' ваш_файл.txt
Объяснение:
- Здесь мы используем
-E
для включения расширенных регулярных выражений. - Мы ищем последовательность "00 00" с двумя числами после, а затем заменяем следующие два числа на "XX".
3. Использование perl
perl
также предоставляет возможность обрабатывать текстовые потоковые данные и может быть очень эффективным:
perl -pe 's/(00 00 [0-9]+ [0-9]+)\s+[0-9]+\s+[0-9]+/$1 XX XX/' ваш_файл.txt
Объяснение:
- Здесь мы используем регулярное выражение для поиска "00 00" и двух последовательных чисел.
- Затем мы заменяем два следующих числа на "XX".
Вывод
Каждый из предложенных подходов имеет свои преимущества. Если вам нужно более сложное условие обработки данных, используйте awk
. Если вам нужна простая подстановка, sed
или perl
подойдут идеально. Учитывайте также, что использование awk
может дать вам больше гибкости для дальнейшей обработки строк, тогда как sed
и perl
более эффективны для простых операций замены.
Заключение
Выбор инструмента зависит от ваших конкретных нужд и предпочтений. Рекомендуется протестировать каждое решение, чтобы выбрать то, которое лучше всего соответствует вашим ожиданиям по производительности и простоте синтаксиса.