Замените все двойные кавычки только в N-м столбце

#linux #awk #sed #replace

Вопрос:

У меня есть такой файл

 abc|def||ghi|jklm||uv||xyz
abc|def||ghi|jklm|nopqrst|uv||xyz
abc|def||ghi|jklm|nopq"rst|uv||xyz
abc|def||ghi|jklm|"nopqrst"|uv||xyz
abc|def||ghi|jklm|"nopq"rst"|uv||xyz
abc|def||ghi|jklm|"nopq"r"st"|uv||xyz
 

6 — ю колонку можно было бы заключить в двойные кавычки. Я хочу заменить все вхождения двойных кавычек в этом поле на обратную косую черту-двойную кавычку («)

Я хочу, чтобы мой результат выглядел так

 abc|def||ghi|jklm||uv||xyz
abc|def||ghi|jklm|nopqrst|uv||xyz
abc|def||ghi|jklm|nopq"rst|uv||xyz
abc|def||ghi|jklm|"nopqrst"|uv||xyz
abc|def||ghi|jklm|"nopq"rst"|uv||xyz
abc|def||ghi|jklm|"nopq"r"st"|uv||xyz
 

Я пробовал комбинации ниже, но каждый раз заканчивался коротко

 sed -i 's/"/\"/2' file.txt (this replaces only 2nd occurrence)
sed -i 's/"/\"/2g' file.txt (this replaces only 2nd occurrence and all rest also)
 

В моем файле будут миллионы строк; поэтому мне может понадобиться только команда sed или awk.
Пожалуйста, помогите.

Комментарии:

1. У вас могут быть такие данные, как "abc или xyz" в 6-й колонке? То есть, присутствует только начальная или конечная цитата.

2. Можете ли вы иметь | s в 6-й колонке, например ? "foo|bar" У вас могут быть цитаты в любой другой колонке?

Ответ №1:

Вы можете использовать это awk решение в любой версии awk :

 awk 'BEGIN {FS=OFS="|"} {
   c1 = substr($6, 1, 1)
   c2 = substr($6, length($6), 1)
   s = substr($6, 2, length($6)-2)
   gsub(/"/, "\"", s)
   $6 = c1 s c2
} 1' file

abc|def||ghi|jklm||uv||xyz
abc|def||ghi|jklm|nopqrst|uv||xyz
abc|def||ghi|jklm|nopq"rst|uv||xyz
abc|def||ghi|jklm|"nopqrst"|uv||xyz
abc|def||ghi|jklm|"nopq"rst"|uv||xyz
abc|def||ghi|jklm|"nopq"r"st"|uv||xyz
 

Комментарии:

1. Спасибо тебе, Анубхава. Это идеально подходит для моих требований.

Ответ №2:

Если это не все, что вам нужно, отредактируйте свой вопрос, чтобы предоставить более репрезентативный образец ввода/вывода, включая случаи, когда это не работает:

 $ sed 's/"/\"/g; s/|\"/|"/g; s/\"|/"|/g' file
abc|def||ghi|jklm||uv||xyz
abc|def||ghi|jklm|nopqrst|uv||xyz
abc|def||ghi|jklm|nopq"rst|uv||xyz
abc|def||ghi|jklm|"nopqrst"|uv||xyz
abc|def||ghi|jklm|"nopq"rst"|uv||xyz
abc|def||ghi|jklm|"nopq"r"st"|uv||xyz
 

Вышесказанное будет работать в любом sed.

Комментарии:

1. Спасибо тебе, Эд Мортон. Ваше решение является более общим и не ограничивается только столбцом № 6. Это, несомненно, будет полезно мне для моей будущей работы. Еще раз спасибо.

Ответ №3:

Это может сработать для вас (GNU sed):

 sed -E 's/[^|]*/namp;n/6            # isolate the 6th field
        h                          # make a copy
        s/"/\"/g                  # replace " by "
        s/\(")n|n\(")/1n2/g # repair start and end "s
        H                          # append amended line to copy
        g                          # get copies to current line
        s/n.*n(.*)n.*n(.*)n.*/21/' file # swap fields
 

Окружите 6-е поле новыми строками и сделайте копию в области удержания.

Замените все " » s » на " » s «и удалите » s «в начале и в конце поля, если поле начинается и заканчивается на " » s

Добавьте измененную строку в копию и замените текущую строку удвоенной строкой.

Используя сопоставление с шаблоном, замените скопированную строку 6-го поля на измененное.