Перенести часть строки: sed, awk, Perl или вырезать, что ли?

Очень ново во всей этой штуке с Unix. В настоящее время я использую оболочку korn, чтобы попытаться отформатировать несколько строк текста.

В моем вводе есть пара строк, которые выглядят примерно так

Date/Time        :- Monday June 03 00:00:00 EDT 2013
Host Name        :- HostNameHere
PIDS             :- NumbersNLetters
Product Name     :- ProductName

Желаемый результат будет следующим:

Date/Time="Monday June 03 00:00:00 EDT 2013" HostName="HostNameHere" PIDS="NumbersNLetters" ProductName="ProductName"

Итак, мне нужно избавиться от любых пробелов в крайнем левом столбце и поместить все в крайний правый столбец между цитатами. Я посмотрел на команду cut и дошел до этого:

Cut -f 1,2 -d -

Это может дать результат типа Date/Time:Monday June 03 00:00:00 EDT 2013, что близко к тому, что я хочу, но не совсем. Я не был уверен, что cut может позволить мне добавлять круглые скобки, и не похоже, что я могу удалить пробелы таким образом.

sed кажется, что это может быть ближе к ответу, но я не смог найти в гугле, как я мог бы просто искать какой-либо шаблон, а не конкретный. Я прошу прощения за невероятно простой вопрос, но чтение документации только уведет вас до того момента, когда у вас начнет болеть мозг ... Если есть какие-то лучшие ресурсы, на которые я должен смотреть, я был бы счастлив, если меня укажут в правильном направлении. Спасибо!


person dsclough    schedule 28.06.2013    source источник
comment
Хотите знать, что вам нужно, например, вывод сверхдлинных строк ...   -  person jm666    schedule 29.06.2013


Ответы (6)


Perl тоже :)

perl -0777 -pe 's/ +(?=.*:-)//g;s/^(.*?):-\s*(.*)\s*/$1="$2" /gm' < file.txt

производит из ввода @ Endoro:

Date/Time="Monday June 03 00:00:00 EDT 2013" HostName="HostNameHere" PIDS="NumbersNLetters" ProductName="ProductName" Date/Time="Monday June 03 00:00:00 EDT 2013" HostName="HostNameHere" PIDS="NumbersNLetters" ProductName="ProductName" Date/Time="Monday June 03 00:00:00 EDT 2013" HostName="HostNameHere" PIDS="NumbersNLetters" ProductName="ProductName" Date/Time="Monday June 03 00:00:00 EDT 2013" HostName="HostNameHere" PIDS="NumbersNLetters" ProductName="ProductName" 

или если хочешь один \n до конца

perl -0777 -nE 's/ +(?=.*:-)//g;s/^(.*?):-\s*(.*)\s*/$1="$2" /gm;say' < file.txt
person jm666    schedule 28.06.2013

Код предназначен только для GNU sed:

sed -nr 's/(.*)\b\s+:-\s(.*)/\1="\2" /;H;s/.*//;${x;:k;s/\n(.*)\n(.*)/\1\2/g;tk;p}' file

..пример вывода:

$cat file
Date/Time        :- Monday June 03 00:00:00 EDT 2013
Host Name        :- HostNameHere
PIDS             :- NumbersNLetters
Product Name     :- ProductName
Date/Time        :- Monday June 03 00:00:00 EDT 2013
Host Name        :- HostNameHere
PIDS             :- NumbersNLetters
Product Name     :- ProductName
Date/Time        :- Monday June 03 00:00:00 EDT 2013
Host Name        :- HostNameHere
PIDS             :- NumbersNLetters
Product Name     :- ProductName
Date/Time        :- Monday June 03 00:00:00 EDT 2013
Host Name        :- HostNameHere
PIDS             :- NumbersNLetters
Product Name     :- ProductName

$sed -nr "s/(.*)\b\s+:-\s(.*)/\1=\"\2\" /;H;s/.*//;${x;:k;s/\n(.*)\n(.*)/\1\2/g;tk;p}" file
Date/Time="Monday June 03 00:00:00 EDT 2013" Host Name="HostNameHere" PIDS="NumbersNLetters" Product Name="ProductName" Date/Time="Monday June 03 00:00:00 EDT 2013" Host Name="HostNameHere" PIDS="NumbersNLetters" Product Name="ProductName" Date/Time="Monday June 03 00:00:00 EDT 2013" Host Name="HostNameHere" PIDS="NumbersNLetters" Product Name="ProductName" Date/Time="Monday June 03 00:00:00 EDT 2013" Host Name="HostNameHere" PIDS="NumbersNLetters" Product Name="ProductName"

В некоторых средах " двойные кавычки" должны быть экранированы обратной косой чертой.

person Endoro    schedule 28.06.2013
comment
тогда слишком сложно :-). Следующая простая цепочка работает в общем sed 's/\s*://' input | sed 's/- / "/' | sed 's/$/" /' | tr -d '\n' - person Fredrik Pihl; 29.06.2013
comment
@FredrikPihl, в моем коде не кирпич, а раньше - кирпичики :-) - person Endoro; 29.06.2013
comment
Я не хочу давать вам +1, сравните ваше решение с простотой awk в этом случае. Возможно позже для сед-мастурбации :-) - person Fredrik Pihl; 29.06.2013
comment
то же самое: OP хочет удалить пробелы из Host Name - person jm666; 29.06.2013

В одну сторону с awk:

awk '{
    gsub(/[[:space:]]+/,"",$1);
    gsub(/.*/,"\"&\"",$2);
    print $1,$2
}
END { print "\n" }' FS=':- ' OFS='\=' ORS=' ' inputFile

ИЛИ однострочный

awk '{gsub(/ /,"",$1);print $1,q$2q}END{print "\n"}' OFS='\=' q='"' FS=' +:- ' ORS=' ' file
person jaypal singh    schedule 28.06.2013
comment
возможно, это неправильно, но OP хочет удалить пробелы из LHS, например. Host Name :- HostNameHere должно быть HostName="HostNameHere" - person jm666; 29.06.2013
comment
@ jm666 Ой, первое решение помогает. Однострочный нет. Починил это. Спасибо, что указали на это. :) - person jaypal singh; 29.06.2013

вы могли бы сделать что-то подобное, чтобы начать

awk '{
  if (NR % 4)
printf("%s ", $0)
  else
printf("%s\n", $0)
}' file

найдено здесь http://www.unix.com/shell-programming-scripting/115070-how-can-i-join-three-lines-into-one-unix.html

затем используйте вырезать

person KeepCalmAndCarryOn    schedule 28.06.2013

По сути, вы хотите применить к своему входу три различных преобразования:

  1. В каждой строке удалите все пробелы перед :-.
  2. В каждой строке замените :-, за которым следует пробел, на =".
  3. В каждой строке добавляйте " в конец.
  4. Замените символы новой строки пробелами.

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

Для выполнения первого шага лучше всего использовать sed. sed работает с регулярными выражениями, о которых вы можете прочитать на Regular-Expressions.info. Поскольку мы хотим удалить пробелы только перед :-, нашему выражению необходимо учитывать его окружение. С этой целью можно использовать утверждение lookbehnd нулевой ширины , чтобы проверить, что шаблон (пробел, обозначенный \s) не заменяет ничего после :- в строке. Однако sed не поддерживает эту функцию регулярных выражений, вместо этого мы будем использовать однострочный perl.

perl -pe 's/\s*(?=.*:-)//g'

Это означает: заменить любые пробелы, за которыми следует :- после любого количества символов, пустой строкой. g означает global и заставляет шаблон заменять все совпадения, а не только первое. Использование perl -pe в идентично sed, но позволяет использовать более изящные регулярные выражения.

Шаг второй немного проще: замените :- плюс любые пробелы на =.

sed 's/:-\s*/="/'

Шаг третий очень простой:

sed 's/$/"/'

Здесь $ означает конец строки. Кстати, две или более sed команды можно объединить в одну, используя ; в качестве разделителя:

sed 's/:-\s*/="/;s/$/"/'

Это будет немного быстрее. Я мог бы посоветовать вам использовать sed и для последнего шага, но я воспользуюсь этой возможностью, чтобы показать вам другую ключевую команду: tr. tr - это сокращение от translate и заменяет любой отдельный символ другим. Это намного быстрее, чем sed.

tr '\n' ' '

Здесь \n обозначает символ новой строки (код ASCII 0x0a).

Итак, собираем все вместе:

cat input | perl -pe 's/\s*(?=.*:-)//g' | sed 's/:-\s*/="/;s/$/"/' | tr '\n' ' '

Для дальнейшего изучения вы можете прочитать страницы руководства sed и tr. Для этого введите следующие команды:

man sed
man tr
person Albert Peschar    schedule 28.06.2013
comment
sed поддерживает все, что вы говорите, но не поддерживает. - person Endoro; 29.06.2013
comment
Ну, похоже, он не поддерживает поиск с использованием синтаксиса Perl. Но могут быть и другие способы получить такие же результаты, например, опубликованная вами команда. Лично я бы порекомендовал освоить регулярные выражения в стиле Perl, поскольку они в конечном итоге более полезны, чем любая sed магия когда-либо будет. - person Albert Peschar; 29.06.2013
comment
В любом случае, вы придумали довольно причудливую команду. Итак, если вы можете освоить синтаксис, это хорошо для вас. ;) - person Albert Peschar; 29.06.2013

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

sed -r ':a;s/ (\S*:-.*)$/\1/;ta;s/:-\s*/="/;s/$/"/;1h;1!H;$!d;x;s/\n/ /g' file
  • :a;s/ (\S*:-.*)$/\1/;ta удалите все пробелы, оставшиеся от :-
  • s/:-\s*/="/ заменить :- на ="
  • s/$/"/ вставить " в конце строки.
  • 1h;1!H для первой строки вставьте пространство шаблона (PS) в пространство удержания (HS). Затем добавьте PS к HS.
  • $!d все, кроме последней строки, удалите PS и прочтите следующую строку в PS.
  • x в последней строке поменять HS на PS
  • s/\n/ /g замените все символы новой строки пробелами и распечатайте полученную строку.
person potong    schedule 29.06.2013