чи можемо ми друкувати останнє слово кожного рядка в Linux за допомогою команди sed?


9

припустимо, якщо є файл, що складається з наступних рядків, якщо вони є

12345 567 7878 66

   er3 t45t y6y46y 


 4y6 y656y y5y

   46y6 65y7 y66uyuy

 yy46y6y

Вихід повинен мати такий вигляд:

66

y6y46y

y5y

y66uyuyy

y46y6y

Я спробував назву sed 's/.* //g'файлу команди та декількох інших sedкоманд, але це не працює.

Чи можу я знати, яка саме sedкоманда?


Чи потрібно це використовувати sed?
coffeMug

Відповіді:


8
awk '{print $NF}'
sed 's/[[:blank:]]*$//;s/.*[[:blank:]]//'

Це все ще надрукує порожній рядок для кожного порожнього рядка. Щоб цього уникнути:

awk 'NF{print $NF}'
sed 's/[[:blank:]]*$//;s/.*[[:blank:]]//;/./!d'

Одне альтернативне вираз: sed -n 's/.*[[:blank:]]\+\([^[:blank:]]\+\)[[:blank:]]*$/\1/p'.
jimmij

@jimmij - ця робота не працює, якщо остання не порожня послідовність є також першою і немає пробілів, які передують їй. Також, можливо, ви просто зробите .*в хвіст, ймовірно - ви виключаєте що завгодно, окрім останніх заготовок у будь-якому випадку .*[^[:blank:]].
mikeserv



4

Ти майже там. Просто вкажіть останнє слово:

sed 's/^.* \([^ ][^ ]*\)/\1/g'

Що це робить:

  1. '^. *' видаляє все на початку рядка та будь-яких пробілів.
  2. '\ (...) \' відповідає шаблону і повертає його як \ 1.
  3. '[^]' відповідає будь-якому без пробілу в ньому.

(Відредаговано, щоб додати кращого рішення. Дякую Hildred!)


1
Ось коротший вираз: sed -r 's/.* ([^ ]+)/\1/g'якщо дозволені розширені регулярні вирази, що зазвичай буває.
mkalkov

Коротша версія, використовуючи заміну того, що ви не хочете зберігати, а не те, що ви хочете зберегти:sed 's/.* //'
Uriel

2

Ви можете використовувати якийсь адекватний зразок grepзамість sed, наприклад:

grep -o "[a-Z0-9]*$"

У цьому прикладі [...]містяться діапазони символів, які вважаються підходящими для "слова" (в цьому випадку буквено-цифрові символи можуть бути додані інші символи, деякі з яких потрібно уникати).


3
Це передбачає, що в кінці рядка немає порожнього. a-Zяк діапазон не має особливого сенсу, навіть у локальних системах, що базуються на ASCII. Зауважте, що -oце розширення GNU.
Стефан Хазелас

0

Якщо ви кваліфікуєте слово, щоб означати будь-яку послідовність з 1 або більше непорожніх символів, то відповідь, безумовно, так, і це робиться дуже просто. Це відбувається тому , що [[:blank:]]*і [^[:blank:]]*є логічні доповнення і - при умови , всі символи в рядку є повними - [[:blank:]]*U [^[:blank:]]*можна описати будь-яку можливу рядок в такий же спосіб .*робить.

Якщо в рядку існує неповний символ або недійсна послідовність байтів, то його не можна успішно описати головою до хвоста - як це іноді може траплятися при інтерпретації рядка в неправильному кодуванні. Щоб забезпечити повноцінний символ на байт у будь-якому рядку, локальність C може бути вимушена як:

LC_ALL=C sed ...

... що дозволить уникнути будь - яких проблем , яка описує рядок від голови до хвоста з всеохоплюючим малюнком , такими як .*або([ ]*[^ ]*)*

Повністю доповнюючий візерунок може повторюватися стільки разів, скільки потрібно зліва направо, довжина будь-якої струни приземляється на останнє можливе виникнення без будь-якого розриву шаблону. Це, безумовно, регулярна мова.

BRE:

sed 's/\(\([^[:blank:]]*\)[[:blank:]]*\)*/\2/'

ERE:

sed -E 's/(([^[:blank:]]*)[[:blank:]]*)*/\2/'

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

Зібравши все це, магія відбувається в заміні - посилання повертаються групами \1і \2є останніми явищами кожної. Отже, коли здійснюється заміна, весь рядок замінюється лише останнім явищем у рядку нульового або більше не порожніх символів - або підгрупі \2.

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

b='[:blank:]'

Тепер, щоб надрукувати лише якщо рядок містить один чи більше непорожніх символів, ви можете:

BRE:

sed -n "s/\(\([^$b]*\)[$b]*\)*/\2/;/./p"

ERE:

sed -En "/[^$b]/s/(([^$b]*)[$b]*)*/\2/p"
  1. Справа BRE - підміна завжди виконується, і друкуються лише пробіли з малюнком, принаймні одним символом, що залишився.
  2. Випадок ERE - заміщення проводиться лише коли-небудь на просторі шаблону, що містить принаймні одне не порожнє значення.

Будь-яка форма буде працювати з будь-яким методом - доки синтаксис правильний.

-nПеремикач відключає автоматичний друку з шаблону, і pпрапор в s///ubstitution або /адресних /команд видає його результати тільки в разі успіху.

Ця ж логіка може бути застосована для отримання будь {num}- якого явища, а також, як:

BRE:

sed -n "s/\([$b]*\([^$b]\{1,\}\)\)\{num\}.*/\2/p"

ERE:

sed -En "s/([$b]*([^$b]+)){num}.*/\2/p"

... де numобидва regexps можуть бути замінені цифрою, щоб друкувати лише {num}вказане виникнення послідовності непорожніх символів. Тут дещо інша форма використовується для того, щоб підрахунок не був перекошений для провідного простору в рядку.

Зверніть увагу , що -Eперемикач ERE до sedпідтримуються як в BSD і GNU версії, хоча це не є ще POSIX стандартного синтаксису.


Приємні пояснення, приємний хак, але зауважте, що він не працюватиме з традиційними sed реалізаціями (наприклад, Solaris / usr / bin / sed), і буде дорожчим, ніж більш простий підхід (вичерпує пам'ять з вхідними рядками довжиною більше 25 символів з наприклад, sed_su3з інструментального інструмента Heirloom). Тож хоч відповідь мені подобається, я б не рекомендував такий підхід.
Стефан Шазелас

Схоже, це також не працює у FreeBSD.
Стефан Шазелас

@ StéphaneChazelas - так, ця робота справді жахлива для такої речі, але вона може бути дуже ефективною для вибору нумерованих подій. І для кінця рядка справа s/.* \([^[:blank:]]\{1,\}\).*/\1/набагато краща, але складніше, коли задіяно кілька рядків. Однак днями я виявив, що це 's/\(\n\)*/\1/g;s/\n\(\n.*\)*/&&/[num];s///[samenum]може досить ефективно підкреслити це. У будь-якому випадку, доки в логіці немає явної помилки, то я щасливий - я просто думав, що, мабуть, щось пропустив.
mikeserv

@ StéphaneChazelas - о, а щодо старших seds - це трохи дивно - це повинно звучати відповідно до стандарту. xrat каже ... Розробники стандартів розглядали загальну історичну поведінку, яка підтримувала "\n*", але ні "\n\{min,max\}", "\(...\)*", або "\(...\)\{min,max\}"як ненавмисний результат конкретної реалізації, і вони підтримували як дублювання, так і інтервальні вирази після субекспресій та зворотних посилань.
mikeserv

@ StéphaneChazelas - І стандарт говорить ... Якщо субекспресія, на яку посилається зворотний посилання, відповідає більш ніж одному рядку через зірочку ( '*' )або інтервальний вираз (див. Пункт (5)), зворотний посилання повинен відповідати останньому (крайній правий край ) цих рядків. Я впевнений, що я протестував цю програму, minisedхоча я, звичайно, тестував щось дивне minisedв інший день.
mikeserv

0
sed 's/^ star.star //'  filename  or sed 's/^[[:blank:]]star.star[[:blank:]]//' filename

Аналіз:

  • s - замінник

  • / --початок вираження шукати

  • ^ - від початку рядка

  • [[:blank:]]* - якщо на початку рядка є пробіли

  • .* - будь-який персонаж

  • [[:blank:]] - і порожній символ

  • / - початок вираження підміняти

  • / - кінець синтаксису команд

PS: Я написав зірку в товариші.


Як це можна застосувати до даних, наведених у запитанні?
Кусалаланда

@Scott s/.*[[:blank:]]//працює, якщо в кінці рядка немає пробілів.
Кусалаланда

-1

Так. Наступна команда sed спочатку видаляє всі пробіли пробілів ( s/ *$//), а потім все до останнього пробілу ( s/.* //). Напевно, варто замінити буквальний пробіл [[:blank:]]на, щоб захопити вкладки та інші символи, що нагадують простір.

$ echo "  aaa bbb cc   " | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "  aaa bbb cc" | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "aaa bbb cc   " | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "aaa bbb cc" | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "  cc  " | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "cc" | sed -e 's/ *$//' -e 's/.* //'
cc

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