Как обрезать начальные и конечные пробелы в каждой строке некоторого вывода?

155

Я хотел бы удалить все начальные и конечные пробелы и вкладки из каждой строки в выводе.

Есть ли простой инструмент, как trimя мог бы передать свой вывод?

Пример файла:

test space at back 
 test space at front
TAB at end  
    TAB at front
sequence of some    space in the middle
some empty lines with differing TABS and spaces:





 test space at both ends 
rubo77
источник
1
Для тех, кто ищет здесь решение для удаления новых строк, это другая проблема. По определению новая строка создает новую строку текста. Поэтому строка текста не может содержать символ новой строки. Вопрос, который вы хотите задать, заключается в том, как удалить новую строку из начала или конца строки: stackoverflow.com/questions/369758 или как удалить пустые строки или строки, которые являются просто пробелами
Тони

Ответы:

201
awk '{$1=$1;print}'

или короче:

awk '{$1=$1};1'

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

Это работает, потому что когда вы назначаете что-то одному из полей , awkперестраивает всю запись (как напечатано print), объединяя все поля ( $1, ..., $NF) с OFS(пробел по умолчанию).

1 (и, возможно, другие пустые символы в зависимости от локали и awkреализации)

Стефан Шазелас
источник
2
Точка с запятой на втором примере лишняя. Могли бы использовать:awk '{$1=$1}1'
Брайан
Интересно ... Никакая точка с запятой не поддерживается gawk, mawk и OS X's awk. (По крайней мере, для моих версий (1.2, 4.1.1 и 20070501 соответственно)
Брайан
1
Единственное, что мне не нравится в этом подходе, это то, что вы теряете повторяющиеся пробелы в строке. Например,echo -e 'foo \t bar' | awk '{$1=$1};1'
user.friendly
2
echo ' hello ' | xargs
JREAM
44

Команду можно сжать примерно так, если вы используете GNU sed:

$ sed 's/^[ \t]*//;s/[ \t]*$//' < file

пример

Вот приведенная выше команда в действии.

$ echo -e " \t   blahblah  \t  " | sed 's/^[ \t]*//;s/[ \t]*$//'
blahblah

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

$ echo -e " \t   blahblah  \t  " | sed 's/^[ \t]*//;s/[ \t]*$//' | hexdump -C
00000000  62 6c 61 68 62 6c 61 68  0a                       |blahblah.|
00000009

Классы персонажей

Вы также можете использовать имена классов символов вместо буквального перечисления наборов, таких как [ \t]:

$ sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//' < file

пример

$ echo -e " \t   blahblah  \t  " | sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//'

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

 [[:alnum:]]  - [A-Za-z0-9]     Alphanumeric characters
 [[:alpha:]]  - [A-Za-z]        Alphabetic characters
 [[:blank:]]  - [ \x09]         Space or tab characters only
 [[:cntrl:]]  - [\x00-\x19\x7F] Control characters
 [[:digit:]]  - [0-9]           Numeric characters
 [[:graph:]]  - [!-~]           Printable and visible characters
 [[:lower:]]  - [a-z]           Lower-case alphabetic characters
 [[:print:]]  - [ -~]           Printable (non-Control) characters
 [[:punct:]]  - [!-/:-@[-`{-~]  Punctuation characters
 [[:space:]]  - [ \t\v\f]       All whitespace chars
 [[:upper:]]  - [A-Z]           Upper-case alphabetic characters
 [[:xdigit:]] - [0-9a-fA-F]     Hexadecimal digit characters

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

Рекомендации

SLM
источник
Обратите внимание, что [[:space:]]это не эквивалентно [ \t]в общем случае (Unicode и т. Д.). [[:space:]]вероятно, будет намного медленнее (поскольку в юникоде гораздо больше типов пробелов, чем просто ' 'и '\t'). То же самое для всех остальных.
Оливье Дюлак
sed 's/^[ \t]*//'не является портативным На самом деле POSIX даже требует, чтобы это убирало последовательность пробелов, обратной косой черты или tсимволов, и это то же самое делает GNU sed, когда POSIXLY_CORRECTнаходится в среде.
Стефан Шазелас
Что если я хочу обрезать символы новой строки? '\ n \ n text \ n \ n'
Евгений Бирюков
Мне нравится решение sed из-за отсутствия других побочных эффектов, как в решении awk. Первый вариант не работает, когда я попробовал его в bash на OSX jsut, но версия класса персонажей работает:sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//'
Tony
@EugeneBiryukov см. Мой комментарий к исходному сообщению
Тони
23

Как предложил Стефан Шазелас в принятом ответе, теперь вы можете
создать скрипт /usr/local/bin/trim:

#!/bin/bash
awk '{$1=$1};1'

и дать этому файлу права на выполнение:

chmod +x /usr/local/bin/trim

Теперь вы можете передать каждый вывод, trimнапример:

cat file | trim

(для комментариев ниже: я использовал это раньше: while read i; do echo "$i"; done
который также работает нормально, но менее производительно)

rubo77
источник
1
Удачи, если ваш файл огромен и / или содержит обратную косую черту.
don_crissti
1
@don_crissti: не могли бы вы прокомментировать немного больше? Какое решение лучше подойдет для больших файлов, и как я могу изменить свое решение, если файл содержит обратную косую черту?
rubo77
3
Вы должны будете использовать , while read -r lineчтобы сохранить обратную косую черту и даже тогда ... . Что касается огромных файлов / скорости, действительно, вы выбрали худшее решение. Я не думаю, что там что-то хуже. См. Ответы на вопрос: почему использование цикла оболочки для обработки текста является плохой практикой? включая мой комментарий к последнему ответу, где я добавил ссылку на тест скорости. Эти sedответы здесь прекрасно IMO и гораздо лучше , чем read.
don_crissti
@don_crissti ... и / или имеет строки, начинающиеся с -и после которых следуют комбинации из 1 или более символов e, E или n, и / или содержит символы NUL. Кроме того, не завершенная строка после последней новой строки будет пропущена.
Стефан Шазелас
1
Вы также можете добавить псевдоним в / etc / profile (или в ~ / .bashrc или ~ / .zshrc и т. Д.). Alias ​​trim = "awk '{\ $ 1 = \ $ 1}; 1'"
Джефф Клейтон,
22

XARGS без аргументов делают это.

Пример:

trimmed_string=$(echo "no_trimmed_string" | xargs) 
Newton_Jose
источник
1
Это также сокращает несколько пробелов в строке, которая не была запрошена в вопросе
roaima
1
@roaima - правда, но принятый ответ также сжимает пробелы (что не было запрошено в вопросе). Я думаю, что реальная проблема здесь в том, что не xargsполучится, если входные данные содержат обратную косую черту и одинарные кавычки.
don_crissti
@don_crissti, что не означает, что принятый ответ правильно отвечает на вопрос, как и было задано. Но в данном случае это не было отмечено как предостережение, тогда как в принятом ответе это было. Надеюсь, я выделил этот факт на тот случай, если он будет актуален для будущего читателя.
Ройма
Это также разбивает на одинарные кавычки, двойные кавычки, символы обратной косой черты. Он также запускает один или несколько echoвызовов. Некоторые реализации echo также будут обрабатывать опции и / или обратную косую черту ... Это также работает только для однострочного ввода.
Стефан Шазелас
17
sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'

Если вы читаете строку в переменную оболочки, readделайте это уже, если не указано иное .

жилль
источник
1
+1 за read. Так что, если вы читаете в то время как читать это работает:cat file | while read i; do echo $i; done
rubo77
1
@rubo за исключением того, что в вашем примере переменная без кавычек также обрабатывается оболочкой. Используйте, echo "$i"чтобы увидеть истинный эффект отread
roaima
13

Если вы храните строки как переменные, вы можете использовать bash для выполнения работы:

удалить начальные пробелы из строки:

shopt -s extglob
echo ${text##+([[:space:]])}

удалить конечные пробелы из строки:

shopt -s extglob
echo ${text%%+([[:space:]])}

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

echo ${text//[[:space:]]}
Лукаш Райчел
источник
Удаление всех пробелов из строки - это не то же самое, что удаление начальных и конечных пробелов (как в вопросе).
Кэтпноз
Это лучшее решение - для него требуются только встроенные команды bash и никаких внешних ветвлений процессов.
user259412
2
Приятно. Скрипты работают намного быстрее, если им не нужно загружать внешние программы (такие как awk или sed). Это работает и с «современными» (93u +) версиями ksh.
user1683793
9

Чтобы удалить все начальные и конечные пробелы из заданной строки благодаря инструменту «piped», я могу выделить 3 различных способа, которые не полностью эквивалентны. Эти различия касаются пробелов между словами строки ввода. В зависимости от ожидаемого поведения, вы сделаете свой выбор.

Примеры

Чтобы объяснить различия, давайте рассмотрим эту фиктивную строку ввода:

"   \t  A   \tB\tC   \t  "

тр

$ echo -e "   \t  A   \tB\tC   \t  " | tr -d "[:blank:]"
ABC

trдействительно простая команда. В этом случае он удаляет любой пробел или символ табуляции.

AWK

$ echo -e "   \t  A   \tB\tC   \t  " | awk '{$1=$1};1'
A B C

awk удаляет начальные и хвостовые пробелы и сжимает в один пробел каждый пробел между словами.

СЕПГ

$ echo -e "   \t  A   \tB\tC   \t  " | sed 's/^[ \t]*//;s/[ \t]*$//'
A       B   C

В этом случае sedудаляет начальные и хвостовые пробелы, не касаясь пробелов между словами.

Примечание:

В случае одного слова в строке, trделает работу.

frozar
источник
Ни один из этих уравновешивающих трейлингов / ведущих
новых
+1 за список решений с их (иногда неожиданным) выводом.
Тони
@ user61382 это довольно поздно, но смотрите мой комментарий к оригинальному сообщению.
Тони
@highmaintenance: используйте [:space:]вместо [: blank:] команду tr, например:, ... | tr -d [:space:]для удаления новых строк. (см man tr)
tron5
6

sed - отличный инструмент для этого:

                        # substitute ("s/")
sed 's/^[[:blank:]]*//; # parts of lines that start ("^")  with a space/tab 
     s/[[:blank:]]*$//' # or end ("$") with a space/tab
                        # with nothing (/)

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

<file sed -e 's/^[[...

или действуя по нему «встроенно», если вы sedиспользуете GNU:

sed -i 's/...' file

но изменение источника таким способом «опасно», так как может быть невосстановимым, когда он не работает должным образом (или даже когда это работает!), поэтому сначала создайте резервную копию (или используйте, -i.bakчто также имеет преимущество, которое переносимо на некоторые BSD sed) !

Майкл Даррант
источник
2

команда перевода будет работать

cat file | tr -d [:blank:]
Srinagesh
источник
4
Эта команда неверна, так как она удаляет все пробелы из файла, а не только начальные / конечные пробелы.
Брайан Редберд
@BrianRedbeard Вы правы. Это все еще полезный ответ для монолитной строки без пробелов.
Энтони Ратледж
0

Если строка, которую вы пытаетесь обрезать, является короткой и непрерывной / непрерывной, можно просто передать ее в качестве параметра любой функции bash:

    trim(){
        echo $@
    }

    a="     some random string   "

    echo ">>`trim $a`<<"
Output
>>some random string<<
Субрата Дас
источник