Я хочу заменить точку в поле заголовка (поле2) csv точкой, за которой следует пробел:
Csv пример:
8389383, hello my.friend,839083083,3390903
Предполагаемый результат:
8389383, hello my. friend,839083083,3390903
Я могу успешно заменить точку в csv пробелом, используя только эту строку:
sed -r ':b s/^([^,]*,[^,]*)\./\1 /g; t b' csv
Однако я хочу заменить точку на точку, за которой следует пробел. Я пытался:
sed -r ':b s/^([^,]*,[^,]*)\./\1. /g; t b' csv
Но это зависает и результата не дает.
Что я могу добавить в строку, чтобы разрешить это?
РЕДАКТИРОВАТЬ. Чтобы добавить, в поле 2 (поле заголовка) может быть более одной точки, которую я хочу заменить. Я также не хочу, чтобы это правило применялось к любым другим полям в CSV.
4 ответа
awk
лучше всего подходит для такого рода работ
Для замены всех точек во втором поле выполните
awk -v FS="," -v OFS="," '{gsub(/\./,". ",$2)}1' file.csv > tmpfile && mv tmpfile file.csv
8389383, hello my. friend,839083083,3390903
8389383, hello my. fri. end,839083083,3390903
Это может сработать для вас (GNU sed):
sed -r ':a;s/^([^,]*,[^,.]*)\./\1\n/;ta;s/\n/. /g' file
Хитрость заключается в том, чтобы превратить .
в something else
(я предпочитаю символ новой строки, поскольку он уникален по дизайну seds), а затем глобально изменить это something else
на whatever
в качестве последняя операция на линии.
Альтернативой является копирование линии, изменение части и рекомбинация линии, используя части из копии, которые вы не хотите изменять:
sed -r 's/,/\n/;s/,/\n/;h;s/\./& /g;G;s/.*\n(.*)\n.*\n(.*)\n.*\n/\2,\1,/' file
$ cat file.csv
8389383, hello my.friend, 839083083, 3390903
8389383, hello my.fri.end, 839083083, 3390903
$ perl -i -F, -e '$F[1] =~ s/\./. /g; print join(",",@F)' file.csv
$ cat file.csv
8389383, hello my. friend, 839083083, 3390903
8389383, hello my. fri. end, 839083083, 3390903
-F,
разделяет каждую строку на,
и сохраняет ее в массиве@F
. Параметр-F
неявно устанавливает-a
и-n
. Дополнительную информацию см. В разделе Командные переключатели perldoc.join(",",@F)
присоединяются к массиву с,
в качестве разделителя. Не знаю, есть ли в perl неявный способ распечатать измененный массив с тем же разделителем ввода
Как насчет этого:
sed -i -e 's/^\([^,]*,[^.,]*\)\.\([^,]*\)/\1. \2/' file.csv
Изменить . Если в поле указано несколько точек, вы не можете сделать это с помощью sed
. А вот однострочник perl
:
perl -i -pe 'sub t {($s)=@_; $s=~s/\./. /g; $s}; s/^[^,]*,\K([^,]*)/t($1)/e;' file.csv
Объяснение: С помощью команды s///
мы находим первое поле ([^,]*,
), пропускаем его (\K
), а затем находим второе поле (([^,]*)
). Для этого поля мы выполняем функцию t
, которая выполняет простую подстанцию.
Похожие вопросы
Новые вопросы
bash
Этот тег предназначен для вопросов о сценариях, написанных для командной оболочки Bash. Сценарии оболочки с синтаксисом или другими ошибками, пожалуйста, проверьте их на https://shellcheck.net, прежде чем публиковать здесь. Вопросы об интерактивном использовании Bash, скорее всего, будут актуальны на Unix & Linux Stack Exchange или Super User, чем на Stack Overflow.