Замініть декілька пробілів одним, використовуючи лише "tr"


71

У мене є файл f1.txt:

ID     Name
1      a
2         b
3   g
6            f

Кількість пробілів не фіксована. Який найкращий спосіб замінити всі пробіли на один простір лише за допомогою tr?

Ось що я маю досі:

cat f1.txt | tr -d " "

Але вихід:

IDName
1a
2b
3g
6f

Але я хочу, щоб це виглядало так:

ID Name
1 a
2 b
3 g
6 f

Будь ласка, намагайтеся уникати sed.


6
Чому так важливо уникати sed? Використовуйте будь-які роботи!
Девід Річербі

7
Тому що я знаю, як це зробити sed. Хотіли знати інші способи
:)

Відповіді:


106

З tr, використовуйте sпараметр повторення в черзі :

$ tr -s " " < file
ID Name
1 a
2 b
3 g
6 f

Або ви можете використовувати awkрішення:

$ awk '{$2=$2};1' file
ID Name
1 a
2 b
3 g
6 f

Коли ви змінюєте поле в записі, awkперебудовуйте $0, приймає всі поля і стискає їх разом, розділених на OFS, що є пробілом за замовчуванням.

Це дозволить видавити послідовності пробілу та вкладок (і, можливо, інших порожніх символів залежно від місцевості та реалізації awk) в один простір, але також видалить провідні та кінцеві пробіли з кожного рядка.


1
Це теж чудове рішення. . . Я не знаю, яку вибрати зараз: / @Gnouc
gkmohit

Не соромтеся вибирати будь-яке рішення, яке вам подобається, і воно працює для вас. Зауважте, що моє рішення відрізняється від відповіді @ polym.
cuonglm

1
:)) так! Відповідь @Gnouc дійсно динамічна, тому що він використовує awk, він може робити все, що завгодно. Ви також можете прийняти його рішення. Тільки одне: Gnouc, чи можете ви пояснити, що робить формат awk у вашій команді? Ви також можете додати вкладки / пробіли, щоб результат відповідав очікуваному результату Unknown?
полим

1
@polym: Останнє редагування Невідомого, здається, хоче лише один пробіл, а не вихід, як column -tце робиться. Додати пояснення для awk.
cuonglm

4
Тут є невелика різниця. trзамінить два пробіли в кінці рядка одним пробілом. awkвидалить усі пробіли.
Енн ван Россум

19

Просто використовуйте column:

column -t inputFile

Вихід:

ID  Name
1   a
2   b
3   g
6   f

Чудова та швидка відповідь :)
gkmohit

1
@ Невідомий Чудово бути на сервісі :)!
полім

1
@Gnouc вау круто, стовпець також бере аргумент як файл. приємно дякую!
полім

Як я можу отримати другий стовпець, лише якщо хочу? Я спробував column -t f1.txt | cut -d " " -f2 Але не було рішення, яке я очікував
gkmohit

2
Використовуйте awk тоді: column -t file | awk '{print $2}'друкує лише другий стовпчик
polym

8

Якщо ви хочете видавити "білий пробіл", ви хочете використовувати попередньо визначені набори символів tr ": blank:" (горизонтальна вкладка пробілу та пробіл) або ": space:" (вертикальна пробіл):

/bin/echo -e  "val1\t\tval2   val3" | tr -s "[:blank:]"

Приклади наводили на Red Hat 5 (GNU tr).

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

Як вказує другий коментар дастробу, я пропустив формулювання на сторінці чоловіка:

 -s uses the last specified SET, and occurs after translation or deletion.

Це дозволяє усунути першу тр. Кудо знущається за свої терпіння перед моєю щільністю.

Раніше розбирався порт з конфігурації Redis. файл:

grep "^port" $redisconf | tr "[:blank:]" " " | tr -s "[:blank:]"  | cut -d" " -f2

Після того, як SET2 задається за допомогою стискання:

grep "^port" $redisconf | tr -s "[:blank:]" " " | cut -d" " -f2

Вихід:

6379

Детальніше про нюанси пробілу

Продемонструйте, що стискання поодинці не вдається, коли задіяні послідовні змішані символи, які потрапляють у [: blank:] клас символів:

 /usr/bin/printf '%s \t %s' id myname | tr -s "[:blank:]"  | od -cb
0000000   i   d      \t       m   y   n   a   m   e
        151 144 040 011 040 155 171 156 141 155 145
0000013

Примітка. Мої два рядкові поля у форматі printf розділені 1 пробілом, 1 вкладкою, 1 пробілом. Після видавлювання ця послідовність все ще існує. На виході октального відвалу це представлено послідовністю ascii 040 011 040.


1
Вам справді потрібно tr "[:blank:]" " " | tr -s "[:blank:]"? Я думаю, що першої частини буде достатньо, тобто tr "[:blank:]" " "оскільки вона нормалізує пробіл і вже робить заміну. На сторінці man: "Видавіть кілька входів символів [...] Це відбувається після завершення видалення та перекладу."
dastrobu

2
так '' -tr "[: blank:]" "" 'повинен зробити це, він спочатку переводить усі пробіли в пробіли, а потім видаляє пробіли. Немає потреби в секунді'tr´.
dastrobu

1
Я спробував printf 'ID \t Name\n' | tr -s "[:blank:]" " " | od -cb(як запропонував @dastrobu) і отримав ID Name\nодним пробілом) як вихід. Ви насправді спробували це, @ user3183018?
Скотт

1
Добре, дозвольте спробувати сказати це ще раз. Я зробив printf 'ID␣\t␣Name\n' | tr -s "[:blank:]" "␣"  (як запропонував @dastrobu), де представляє пробіл, і я отримав ID␣Name\n(з одним простором) як вихід. Це точно так само, як у вашому прикладі "Port <SPACE> <TAB> <SPACE> 6379", за винятком того, що я використовував рядки заголовка з питання. Мені цікаво, чи намагалися ви  tr -s "[:blank:]"(без остаточного "␣"аргументу).
Скотт

1
Коли я це роблю printf 'ID \t Name\n' | od -cb, він показує, що саме слід: ID ⁠  \t ⁠  N a m e \n(тобто,  ID 040 011 040 N a m e\n). Тим часом, за власними доказами, ви робите саме ту помилку, яку я здогадався, що ви: ви запускаєте tr -s "[:blank:]"(тобто,  trз одним варіантом та  одним аргументом) замість команди, яку ми @dastrobu представили вже чотири рази: tr -s '[:blank:]' '␣'(тобто  trз одним варіантом і  двома аргументами ).
Скотт

5

Кому потрібна програма (крім оболонки)?

while read a b
do
    echo "$a $b"
done < f1.txt

Якщо ви хочете, щоб значення у другому стовпці розташовувалися в рядку, як у відповіді поліма column, використовуйте printfзамість echo:

while read a b
do
    printf '%-2s %s\n' "$a" "$b"
done < f1.txt

1
По-перше, якщо порівнювати з tr - це жахливо низька ефективність пропозицій, якщо тільки вхід не надто малий занадто переважає крихітну вартість trвиклику ', - це не кажучи вже про те, на скільки більше роботи потрібно писати. Нарешті, чи не сказали б ви, що ця публікація насправді не відповідає на запитання? Який найкращий спосіб замінити всі пробіли на один пробіл, використовуючи лише tr?
mikeserv

1
І крім того - ти не міг легше просто щось зробити $IFS? Може бути , як: IFS=' <tab>' set -f ; echo $(cat <file)?
mikeserv

2

Це старе питання і вирішується багато разів. Тільки для повноти: У мене був подібний випуск, але хотів передати лінії по трубі до іншої програми. Я використовував xargs .

-L max-lines
   Use at most max-lines nonblank input lines per command line.
   Trailing blanks cause an input line to be logically continued 
   on the next input line.  Implies -x.

так cat f1.txt | xargs -L1здається, виводиться саме те, що ти хочеш.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.