Как удалить знак конца строки (используя sed / awk) однострочного текстового файла? - PullRequest
0 голосов
/ 25 февраля 2020

Я смог передать функцию php списком URL-адресов (на Raspberry Pi 3) только в том случае, если «список» представляет собой текстовый файл, содержащий одну строку (URL) без конечного конца знак ("$"). Я пробовал

sed -e 's/\r$//g'

и

sed -e 's/^M//g'

, но мне удалось удалить только конечный "$" вручную в текстовом редакторе, перейдя к последней (т.е. второй) строке файл и нажатие клавиши backspace на клавиатуре.

Нет проблем разбить мастер-файл, содержащий сотни URL-адресов, на однострочные файлы и вызывать функцию php как файл за раз, но это должно быть другой простой способ (sed, awk?) удалить конечный «$» в конце (единственной) строки в файле.

1 Ответ

0 голосов
/ 25 февраля 2020

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

Некоторые термины / определения:

  • \r - выход последовательность, используемая в сценариях для генерации или сопоставления символа CR (возврат каретки) ^M (control-M), ASCII 13
  • \n - это escape-последовательность, используемая в сценариях для генерации или сопоставления LF (перевод строки) ^J (control-J), ASCII 10
  • $ - это метасимвол регулярного выражения, используемый в сценариях для обозначения end-of-string (который часто также является концом ), а также используется инструментами для указания end-of-line при отображении текста.
  • \n (т. е. только LF) считается новой строкой в ​​UNIX
  • \r\n (то есть CRLF) считается новой строкой в ​​DOS (см. Почему вывод моего инструмента перезаписывается и как я могу это исправить? )

Итак, когда вы сделайте:

$ printf 'foo\n' | cat -vE
foo$

, что не означает, что в конце foo есть $, просто cat отображает $, чтобы показать вам, где находится конец строки. Когда вы делаете:

$ printf 'foo\r\n' | cat -vE
foo^M$

^M (control-M) явно показывает вам символ CR (возврат каретки), сгенерированный \r, но $ равен явно не показывает вам символ ^J (control-J), который LF (перевод строки) генерирует \n, вместо этого он специально отображает другой символ $, чтобы показать вам конец линия. Если бы он показывал вам ^J s, то все было бы объединено в одну строку, которую было бы трудно прочитать. Рассмотрим простоту чтения:

$ printf 'the\nquick\nbrown\nfox\n' | cat -vE
the$
quick$
brown$
fox$

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

$ printf 'the\nquick\nbrown\nfox\n' | some_other_tool
the^Jquick^Jbrown^Jfox^J

Вы никогда не сможете выполнить одно из следующих действий:

$ printf 'foo\nbar\n' | sed 's/$//' | cat -vE
foo$
bar$

$ printf 'foo\nbar\n' | sed 's/\n//' | cat -vE
foo$
bar$

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

Вы можете спросить - если sed потребляет LF при чтении ввода, то почему в конце каждой строки вывода есть LF? Ответ заключается в том, что sed добавляет LF к каждой выходной строке, так что он выводит действительный текстовый файл POSIX (без завершения LF у вас нет текстового файла POSIX и, следовательно, то, что любой последующий инструмент делает с ним, является неопределенным поведением).

Однако вы можете удалить LF, если используете инструмент, который не читает по одной строке за раз. GNU sed имеет опцию -z для чтения текста, разделенного NUL, вместо текста, разделенного LF, и в этом режиме вы можете удалить LF символов:

$ printf 'foo\nbar\n' | sed -z 's/\n//' | cat -vE
foobar$

, и теперь вы можете увидеть, как $ (метасимвол конца строки) отличается от \n (escape-последовательность, соответствующая символу LF):

$ printf 'foo\nbar\n' | sed -z 's/$//' | cat -vE
foo$
bar$

$ printf 'foo\nbar\n' | sed -z 's/\n/<LF>/' | cat -vE
foo<LF>bar$

$ printf 'foo\nbar\n' | sed -z 's/$/<EOS>/' | cat -vE
foo$
bar$
<EOS>$

Итак, быстрый ответ на вопрос «как удалить LF с помощью sed?» это с GNU sed:

$ printf 'foo\nbar\n' | sed -z 's/\n//g'
foobar$

и если у вас нет GNU sed (или даже если вы его используете, так как вышеизложенное будет считывать весь ввод в память сразу, предполагая, что текстовый файл POSIX без NULs) в качестве входных данных), тогда вы должны просто использовать awk:

$ printf 'foo\nbar\n' | awk -v ORS= '1'
foobar$
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...