bash - замініть пробіл новою лінією


70

Як я можу замінити пробіли на нові рядки на вході:

/path/to/file /path/to/file2 /path/to/file3 /path/to/file4 /path/to/file5 тощо ...

Для отримання наступного:

/path/to/file
/path/to/file2
/path/to/file3
/path/to/file4
/path/to/file5

Примітка

Я розміщую це питання, щоб допомогти іншим користувачам, знайти корисну відповідь на UNIX SE було непросто, поки я не почав вводити це питання. Після цього я виявив наступне:

Супутнє питання

Як я можу знайти та замінити новий рядок?



лс / шлях / до / | xargs echo | sed 's / \ s \ + / \ n / g'
SD.

Відповіді:


125

Використовуйте trкоманду

echo "/path/to/file /path/to/file2 /path/to/file3 /path/to/file4 /path/to/file5"\
| tr " " "\n"

Знайдено на веб-сайті http://www.unix.com/shell-programming-scripting/67831-replace-space-new-line.html


1
tr також була моєю першою думкою, хоча існує так багато способів зробити це! Це майже ТОЧНО для чого tr, хоча!
Роб

5
+1, але як коментар: Це не працює, якщо у
файлах

20

У цьому випадку я використовую printf:

printf '%s\n' /path/to/file /path/to/file2 /path/to/file3 /path/to/file4 /path/to/file5

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

printf '%s\n' /path/to/file '/path/to/file with spaces' /path/to/another/file

Трансформація тексту в цілому tr- найкраще, як описано в існуючій відповіді.


1
Швидка записка з майбутнього: дякую за публікацію цього рішення, воно було для мене дуже надійним, порівняно з використанням "ехо".
Лізміт

5

Припустимо, що у вас є рядок з пробілами як роздільники:

newline_separated=${space_separated// /$'\n'}

Однак ви, мабуть, ставите неправильне питання. (Не обов'язково, наприклад, це може з'явитися в makefile.) Список розділених пробілом імен файлів насправді не працює: що робити, якщо одне з назв файлів містить пробіли?

Якщо програма отримує назви файлів як аргументи, не з'єднуйте їх з пробілами. Використовуйте "$@"для доступу один до одного. Хоча echo "$@"друкує аргументи з пробілами між ними, це пов'язано з echo: він друкує свої аргументи пробілами як роздільники. somecommand "$@"передає команди імена файлів як окремі аргументи. Якщо ви хочете роздрукувати аргументи в окремих рядках, ви можете використовувати

printf '%s\n' "$@"

Якщо у вас є імена файлів, розділених пробілом, і ви хочете помістити їх у масив для роботи над ними, ви можете використовувати розширення змінної без котирування, щоб розділити значення на символи IFS(вам потрібно буде вимкнути розширення підстановки за допомогою set -f, інакше глобус шаблони будуть розширені у значенні):

space_separated_list='/path/to/file1 /path/to/file2 /path/to/file3'
IFS=' '; set -f
eval "array=(\$space_separated_list)"
for x in "${array[@]}"; do 

Ви можете інкапсулювати це у функції, яка відновлює -fналаштування та значення, IFSколи це зроблено:

split_list () {
  local IFS=' ' flags='+f'
  if [[ $- = *f* ]]; then flags=; fi
  set -f
  eval "$1=($2)"
  set $flags
}
split_list array '/path/to/file1 /path/to/file2 /path/to/file3'
for x in "${array[@]}"; do 

Зміна правильної відповіді на цю. Я думаю, що правильніше дослідити, як я потрапив до списку, розділеного пробілом, та отримати цю інформацію іншим способом. Для учнів, як я, було б здорово, якщо ви прокоментуєте трохи свій сніпнет, розповівши, що робити такі речі, як локальний var IFS або умова $ - = f . Таких речей людина, яка кілька разів використовує баш, не знає.
лаконбас

@laconbass Я додав коротке пояснення. Подивіться set -fі IFSв керівництві Баша , якщо ви хочете , щоб всі деталі. Дивіться також unix.stackexchange.com/questions/16192 / ...
Gilles

@Guilles Цього короткого пояснення мені достатньо, і я думаю, це буде для багатьох інших. Ty для свого часу
laconbass

налаштування на IFSмісцевому рівні не набуває чинності
Еліран Малька

@EliranMalka Я поняття не маю, що ти розумієш під цим. Якщо сценарій не веде себе так, як ви вважаєте за потрібне, тут можете задати питання.
Жиль

4

Будьте прагматичними, використовуйте sed !!

sed 's/\s\+/\n/g' file

Наведене вище говорить про заміну одного або декількох символів пробілу (\ s +) на новий рядок (\ n)

Це більш-менш:

'substitute /one space or more/ for /newline/ globally'

1
замініть зміну заміною, ось що насправді розшифровується!
Роб

@Rob спасибі, пам’ятайте, що ви можете редагувати відповіді інших.
MGP

1
Якщо у вас є кілька пробілів між текстом, ви отримаєте порожні рядки. Вам потрібно додати "+" після \ s, щоб вказати, що ви хочете відповідати принаймні одному пробілу, призначеному точно одному простору. тобто. sed 's / \ s + / \ n / g'
DarkHeart

4

Як альтернативу trвід @laconbass ви також можете використовувати xargsв цьому випадку:

echo "/path/to/file /path/to/file2 /path/to/file3 /path/to/file4  /path/to/file5"\
| xargs -n1

Перевага полягає в тому, що він працює навіть з декількома пробілами, що trне робить.


0

Ось як я це зробив:

echo "/path/to/file /path/to/file2 /path/to/file3 /path/to/file4 /path/to/file5" | sed 's/ /\
'/g

Зверніть увагу на використання клавіші Enter після зворотної косої риски в sedкоманді.


які плюси і мінуси sedзакінчилися tr?
laconbass

Ваш рівень комфорту :-) Я думаю, що ви можете зробити більше, sedоскільки це редактор, а не просто перекладати символи.
unxnut

4
sedможе зробити набагато більше, але абсолютно непосильний для цього. trє правильним інструментом для цієї роботи, але знання sedта регулярні виразки, безумовно, стануть у нагоді пізніше!
Роб

0

Інший підхід, якщо припустити, що рядок знаходиться в змінній під назвою line:

for path in $line;do echo $path;done

Це використовує той факт, що Bash розбиває свої аргументи на пробіл за замовчуванням, і echoдодає нову лінію до його вводу за замовчуванням.


Я спробував це в своїй системі ubuntu до того, як я опублікував це питання, і не зміг його працювати.
лаконбас

0
echo word1 word2 ... | sed -e 'y/ /\n/;P;D'

- це ще один метод перетворення слів, розділених пробілом, у розділені рядком.


-1

Наступний сценарій простий для розуміння та простий у використанні.

cat filename | tr ' ' '\n' | tee filename

2
Суть вашої відповіді ( tr) така ж, як і у прийнятій відповіді. Крім того, що у вашій відповіді є такі питання: а) команда не позначена чотирма пробілами (-> макет розмітки) б) ваше використання catмарно (ви можете замінити її на < filename tr ' ' '\n'). c) Ваше вихідне ім'я файлу те саме, що ім'я вхідного файлу. З цим ви створюєте перегони даних.
maxschlepzig

1
окрім правильного аналізу maxschlepzig, це не скрипт, а купа зв'язаних команд, що мають ім'я з твердим кодом (як сценарій, сподіваємось, має заголовок із зазначенням оболонки для використання та використання двох параметрів для введення та виведення). Окрім того, що 2 з 3 людей у ​​моєму домогосподарстві не можуть легко зрозуміти. Можливо, це не є репрезентативним, але майте на увазі, що те, що ви самі розумієте (або в цьому випадку думаєте, що розумієте), завжди здається простим.
Антон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.