Как удалить новые строки ('\ n', 0x0A) из непустых строк, используя tr (1)? - PullRequest
5 голосов
/ 18 ноября 2011

У меня есть файл с именем file1 со следующим содержимым:

The answer t
o your question 

A conclusive a
nswer isn’t al
ways possible.

When in doubt, ask pe
ople to cite their so
urces, or to explain

Even if we don’t agre
e with you, or tell y
ou.

Я хотел бы преобразовать file1 в file2 .Последние должны выглядеть следующим образом:

The answer to your question

A conclusive answer isn’t always possible.

When in doubt, ask people to cite their sources, or to explain

Even if we don’t agree with you, or tell you.

В случае, если я просто выполню cat file1 | tr -d "\n" > file2", все символы newline будут удалены.Как удалить только те символы newline , которые находятся на непустых строках с помощью утилиты tr(1)?

Ответы [ 6 ]

9 голосов
/ 18 ноября 2011
perl -00 -lpe 'tr/\n//d'

-00 - режим «абзаца» в Perl, считывающий ввод с одной или несколькими пустыми строками в качестве разделителя. -l добавляет системный символ новой строки к команде печати, поэтому можно безопасно удалить все новые строки во входных данных.

3 голосов
/ 18 ноября 2011

tr не может этого сделать, но sed легко может

sed -ne '$!H;/^$/{x;s/\n//g;G;p;d;}' file1 > file2

. Он находит непустые строки и удерживает их.Затем в пустых строках он удаляет новые строки из сохраненных данных и печатает результат, за которым следует новая строка.Сохраненные данные удаляются, и процесс повторяется.

РЕДАКТИРОВАТЬ:

Для комментария @ potong, вот версия, которая не требует дополнительной пустой строки в конце файла.

sed -ne 'H;/^$/{x;s/\n//g;G;p;};${x;s/\n//g;x;g;p;}' file1 > file2
2 голосов
/ 19 ноября 2011

Новые строки в file1 делятся на четыре класса:

  1. символ новой строки, за которым следует еще один символ новой строки
  2. символ новой строки, которому предшествует символ новой строки
  3. перевод строки в конец файла
  4. сэндвич с новой строки

Удаление первого класса путем чтения всего ввода (опция -000) и замены одной новой строки везде, где мы видим пару из них (s/\n\n/\n/g), дает нам

$ perl -000 -pe 's/\n\n/\n/g' file1 
The answer t
o your question 
A conclusive a
nswer isn’t al
ways possible.
When in doubt, ask pe
ople to cite their so
urces, or to explain
Even if we don’t agre
e with you, or tell y
ou.

Это не то, что мы хотим, потому что первый класс новых строк должен завершать строки в file2.

Мы можем попытаться быть умными и использовать отрицательный взгляд, чтобы удалить переводы строк, которым предшествуют другие переводы строк (второй класс), но вывод неотличим от предыдущего случая, что имеет смысл, потому что на этот раз мы удаляем последний а не первый в каждой паре новых строк.

$ perl -000 -pe 's/(?<=\n)\n//g' file1 
The answer t
o your question 
A conclusive a
nswer isn’t al
ways possible.
When in doubt, ask pe
ople to cite their so
urces, or to explain
Even if we don’t agre
e with you, or tell y
ou.

Несмотря на это, это все еще не то, что мы хотим, потому что переводы строки , перед которыми другие символы перевода строки становятся пустыми строками в file2.

Очевидно, что мы хотим продолжить перевод строки в конце file1.

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

Используя проверочные утверждения Perl , спецификация проста, хотя, возможно, немного пугающая по внешнему виду. «Не предшествует перевод строки» - это негативный след (?<!\n). Используя отрицательный прогноз (?!...), мы не хотим видеть еще одну новую строку или (|) конец ввода ($).

Собрав все вместе, мы получим

$ perl -000 -pe 's/(?<!\n)\n(?!\n|$)//g' file1 
The answer to your question

A conclusive answer isn’t always possible.

When in doubt, ask people to cite their sources, or to explain

Even if we don’t agree with you, or tell you.

Наконец, чтобы создать file2, перенаправьте стандартный вывод.

perl -000 -pe 's/(?<!\n)\n(?!\n|$)//g' file1  >file2
2 голосов
/ 18 ноября 2011

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

# sed '1{h;d};H;${x;s/\([^\n]\)\n\([^\n]\)/\1\2/g;p};d' file

The answer to your question 

A conclusive answer isn't always possible.

When in doubt, ask people to cite their sources, or to explain

Even if we don't agree with you, or tell you.
2 голосов
/ 18 ноября 2011

Если есть символ, который, как вы знаете, не появляется на вашем входе, вы можете сделать что-то вроде этого:

# Assume that the input doesn't contain the '|' character at all
tr '\n' '|' < file1 | sed 's/\([^|]\)|\([^|]\)/\1\2/g' | tr '|' '\n' > file2

Это заменяет все символы новой строки заменяющим символом |;sed затем удаляет все экземпляры |, которые идут после и перед каким-либо другим символом;и, наконец, он заменяет | на новую строку.

0 голосов
/ 18 ноября 2011

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

Вы можете получить пример вывода с помощью sed, но это будетдействительно быть болезненным (я думаю!). edit (sed master @Sorpigal доказывает, что я ошибаюсь!)

Вот решение с awk

/home/shellter:>cat <<-EOS \
| awk 'BEGIN{RS="\n\n"}; { gsub("\n", "", $0) ;printf("%s %s", $0, "\n\n") }'
The answer t
o your question 

A conclusive a
nswer isn’t al
ways possible.

When in doubt, ask pe
ople to cite their so
urces, or to explain

Even if we don’t agre
e with you, or tell y
ou.
EOS


# output
The answer to your question

A conclusive answer isnt always possible.

When in doubt, ask people to cite their sources, or to explain

Even if we dont agree with you, or tell you.

Странно, оно отображается с тройным интервалом, нона самом деле это dbl-spaced.

Awk имеет предопределенные переменные, которые он заполняет для каждого файла, и каждую строку текста, которую он читает, т.е.

RS = RecordSeperator -- normally a line of data, but a configurable value, that when set 
                     to '\n\n' means a blank line, or a typical separation on a paragraph

$0 = complete line of text (as defined by the internal variables RS (RecordSeparator)
                             In this problem, it is each paragraph of data, viewed though
                             as a record.

$1 = first field in text (as defined by the internal variables FS (FieldSeparator)
                           which defaults to (possibly multiple) space chars OR tab char
                          a line with 2 connected spaces chars and 1 tab char has 3 fields)

NF = Number(of)Fields in current line of data (again fields defined by value of FS as 
                                                described above)

(there are many others, besides, $0, $n, $NF, $FS, $RS).

, вы можете программно увеличивать значения, например$ 1, $ 2, $ 3, используя переменную, как в примере кода, например, $ i (i - это переменная, число которой находится в диапазоне от 2 до NF. В начале слова «$» указано значение поля i (то есть $ 2,3 доллара, 4 доллара ...)

Надеюсь, это поможет.

...