Як обрізати пробіли та пробіли з кожного рядка деякого результату?


154

Я хотів би видалити всі провідні та кінцеві пробіли та вкладки з кожного рядка у висновку.

Чи є такий простий інструмент, як 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 

1
Для тих, хто шукає тут рішення про видалення нових рядків, це вже інша проблема. За визначенням новий рядок створює новий рядок тексту. Тому рядок тексту не може містити новий рядок. Питання, яке ви хочете задати, - як видалити новий рядок з початку або в кінці рядка: stackoverflow.com/questions/369758 або як видалити порожні рядки або рядки, які просто пробіли: serverfault.com/questions/252921
Тоні

Відповіді:


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

або коротше:

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

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

Це працює, тому що коли ви присвоюєте щось одному з полів , awkвідновлює весь запис (як надруковано print), приєднуючи всі поля ( $1, ..., $NF) до OFS(пробіл за замовчуванням).

1 (і, можливо, інші порожні символи, залежно від мови та awkреалізації)


2
Точка з комою на другому прикладі зайва. Може використовувати:awk '{$1=$1}1'
Брайан


Цікаво ... Жодна крапка з комою не підтримується gawk, mawk та awk OS X. (Принаймні для моїх версій (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

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

Список літератури


Зверніть увагу, що [[:space:]]це не еквівалентно [ \t]в загальному випадку (unicode тощо). [[:space:]]ймовірно, буде набагато повільніше (оскільки в unicode існує багато більше типів пробілів, ніж просто ' 'та '\t'). Те ж саме для всіх інших.
Олів'є Дулак

sed 's/^[ \t]*//'не є портативним. Практично POSIX навіть вимагає, щоб видалити послідовність пробілу, зворотну косу рису або tсимволів, і це те, що GNU sedтакож робить, коли POSIXLY_CORRECTзнаходиться в оточенні.
Стефан Шазелас

Що робити, якщо я хочу обрізати символи нових рядків? '\ n \ n текст \ n \ n'
Євген Бірюков

Мені подобається розчин sed через відсутність інших побічних ефектів, як у розв'язку awk. Перша варіація не працює, коли я спробував її в bash на OSX jsut зараз, але версія класу персонажів працює:sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//'
Тоні,

@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
що також добре працює, але менш ефективно)


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 тощо ...) псевдонім trim = "awk" {\ $ 1 = \ $ 1}; 1 '"
Джефф Клейтон

22

xargs без аргументів це роблять.

Приклад:

trimmed_string=$(echo "no_trimmed_string" | xargs) 

1
Це також укладає декілька пробілів у рядку, про що не було запитано у запитанні
roaima

1
@roaima - правда, але прийнята відповідь також видаляє пробіли (чого не вимагали у запитанні). Я думаю, що справжня проблема тут полягає в тому, що xargsце не вдасться поставити, якщо вхід містить зворотні косої риски та одинарні лапки.
don_crissti

@don_crissti, що не означає, що прийнята відповідь правильно відповідає на запитання, як було задано. Але в цьому випадку це не було позначено як застереження, тоді як у прийнятій відповіді це було. Я сподіваюся, що я підкреслив той факт, якщо він має значення для майбутнього читача.
roaima

Він також розбивається на одиничні лапки, подвійні лапки, зворотні риси. Він також виконує одну або кілька 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:]]}

Видалення всього пробілу з рядка не є тим самим, як видалення провідних і кінцевих пробілів (як у питанні).
катпноз

Насправді найкраще рішення - для нього потрібні лише вбудовані башти та відсутність зовнішніх вилок.
peterh

2
Приємно. Сценарії працюють швидше, якщо їм не потрібно запускати зовнішні програми (наприклад, awk або sed). Це також працює з "сучасними" (93u +) версіями ksh.
користувач1683793

9

Щоб видалити всі провідні та кінцеві пробіли із заданого рядка завдяки інструменту "трубопровід", я можу виділити 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 видаляє провідні та хвостові пробіли і видавлює в один пробіл пробіли між словами.

sed

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

У цьому випадку sedвидаляйте провідні та хвостові пробіли, не торкаючись проміжків між словами.

Зауваження:

У випадку одного слова на рядок, trвиконує роботу.



+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/^[[...

або діючи на нього "inline", якщо ваш sedGNU:

sed -i 's/...' file

але зміна джерела таким чином "небезпечна", оскільки це може бути неповернутим, коли воно не працює належним чином (або навіть коли це відбувається!), тому спочатку створіть резервну копію (або використовуйте, -i.bakяка також має перевагу переноситись на деякі BSD sed) !


2

команда translate працювала б

cat file | tr -d [:blank:]

4
Ця команда є невірною, оскільки вона видаляє з файлу всі пробіли, а не лише провідні / кінцеві пробіли.
Брайан Руда борода

@BrianRedbeard Ви маєте рацію. Це все ще корисна відповідь на монолітну струну, без пробілів.
Ентоні Рутлідж

0

Якщо рядок, який намагається обрізати, короткий і безперервний / суміжний, його можна просто передати як параметр будь-якій функції bash:

    trim(){
        echo $@
    }

    a="     some random string   "

    echo ">>`trim $a`<<"
Output
>>some random string<<
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.