Замените первые два вхождения пробела запятой, используя sed - PullRequest
5 голосов
/ 08 июля 2011

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

Вот мой ввод:

a b  1 2 3 3 2 1
c d  44 55 66 2355
line http://google.com 100 200 300
ef jh  77 88 99
z y 2 3 33

А вот мой желаемый вывод:

a,b,1 2 3 3 2 1
c,d,44 55 66 2355
line,http://google.com,100 200 300
ef,jh,77 88 99
z,y,2 3 33

Я пытаюсь использовать регулярные выражения perl в команде sed, но не могу заставить ее работать. Сначала я пытаюсь захватить слово, затем пробел, затем другое слово, но это работает только для строк 1, 2 и 5:

$ cat test | sed -r 's/(\w)\s+(\w)\s+/\1,\2,/'
a,b,1 2 3 3 2 1
c,d,44 55 66 2355
line http://google.com 100 200 300
ef jh  77 88 99
z,y,2 3 33

Я также пытаюсь захватить пробел, слово, а затем еще пробел, но это дает мне тот же результат:

$ cat test | sed -r 's/\s+(\w)\s+/,\1,/'
a,b,1 2 3 3 2 1
c,d,44 55 66 2355
line http://google.com 100 200 300
ef jh  77 88 99
z,y,2 3 33

Я тоже пытаюсь сделать это с.? подстановочный знак, но это смешно со строкой 4.

$ cat test | sed -r 's/\s+(.?)\s+/,\1,/'
a,b,1 2 3 3 2 1
c,d,44 55 66 2355
line http://google.com 100 200 300
ef jh,,77 88 99
z,y,2 3 33

Любая помощь очень ценится!

Ответы [ 6 ]

6 голосов
/ 08 июля 2011

Как насчет этого:

sed -e 's/\s\+/,/' | sed -e 's/\s\+/,/'

Возможно, это возможно с помощью одной команды sed, но это, несомненно, простой способ

Мой вывод:

a,b,1 2 3 3 2 1
c,d,44 55 66 2355
line,http://google.com,100 200 300
ef,jh,77 88 99
z,y,2 3 33
4 голосов
/ 08 июля 2011

Попробуйте:

sed -r 's/\s+(\S+)\s+/,\1,/'

Только что заменили \w (один символ "слова") на \S+ (один или несколько символов без пробела) в одной из ваших попыток.

3 голосов
/ 08 июля 2011

Вы можете предоставить несколько команд для одного экземпляра sed, просто указав несколько -e аргументов.

Чтобы сделать первые два, просто используйте:

sed -e 's/\s\+/,/' -e 's/\s\+/,/'

Этов основном выполняет обе команды в строке последовательно, первая выполняет первый блок пробела, вторая выполняет следующую.

Следующая запись показывает это в действии:

pax$ echo 'a b  1 2 3 3 2 1
c d  44 55 66 2355
line http://google.com 100 200 300
ef jh  77 88 99
z y 2 3 33
' | sed -e 's/\s\+/,/' -e 's/\s\+/,/'

a,b,1 2 3 3 2 1
c,d,44 55 66 2355
line,http://google.com,100 200 300
ef,jh,77 88 99
z,y,2 3 33
2 голосов
/ 08 июля 2011

Sed s/// поддерживает способ сказать, какое вхождение шаблона следует заменить: просто добавьте n в конец команды, чтобы заменить только n -ное вхождение.Итак, чтобы заменить первое и второе вхождения пробела, просто используйте его следующим образом:

$ sed 's/  */,/1;s/  */,/2' input
a,b ,1 2 3 3 2 1
c,d ,44 55 66 2355
line,http://google.com 100,200 300
ef,jh ,77 88 99
z,y 2,3 33

EDIT : читая другие предложенные решения, я отметил, что 1 и 2 после s/ */,/ не только не нужно, но и явно неправильно.По умолчанию s/// просто заменяет первое вхождение шаблона.Итак, если у нас есть два идентичных s/// в последовательности, они заменят первое и второе вхождение.Вам нужно просто

$ sed 's/  */,/;s/  */,/' input 

(Обратите внимание, что вы можете поместить две команды sed в одно выражение, если разделите их точкой с запятой. Некоторые реализации sed не принимают точку с запятой после команды s///; используйтев данном случае новая строка для разделения команд.)

1 голос
/ 08 июля 2011

Решение Perl:

perl -pe '$_=join ",", split /\s+/, $_, 3' some.file
0 голосов
/ 08 июля 2011

Не уверен насчет sed / perl, но вот (некрасивое) решение awk. Он просто печатает поля 1-2, разделенные запятыми, затем остальные поля разделяются пробелом:

awk '{
  printf("%s,", $1)
  printf("%s,", $2)
  for (i=3; i<=NF; i++)
    printf("%s ", $i)
    printf("\n")
}' myfile.txt
...