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, пока я не начал набирать этот вопрос. После этого я обнаружил следующее:

Связанный вопрос

Как я могу найти и заменить на новую строку?

laconbass
источник
ls / path / to / | XARGS эхо | 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

laconbass
источник
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ваша лучшая ставка, как описано в существующем ответе.

evilsoup
источник
1
Небольшая заметка из будущего: спасибо за публикацию этого решения, оно было очень надежным для меня, по сравнению с использованием "echo".
Лизмит
5

Предполагая, что у вас есть строка с пробелами в качестве разделителей:

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

Однако вы, вероятно, задаете не тот вопрос. (Не обязательно, например, это может появиться в make-файле.) Разделенный пробелами список имен файлов на самом деле не работает: что если одно из имен файлов содержит пробелы?

Если программа получает имена файлов в качестве аргументов, не объединяйте их с пробелами. Используйте "$@"для доступа к ним один за другим. Хотя echo "$@"печатает аргументы с пробелами между ними, это происходит из-за echo: он печатает свои аргументы с пробелами в качестве разделителей. somecommand "$@"передает имена файлов как отдельные аргументы в команду. Если вы хотите напечатать аргументы в отдельных строках, вы можете использовать

printf '%s\n' "$@"

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

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 . Таких вещей, которые человек, использующий bash несколько раз, не знает.
Laconbass
@laconbass Я добавил краткое объяснение. Посмотрите set -fи IFSв руководстве по bash, если хотите узнать все подробности. См. Также unix.stackexchange.com/questions/16192/…
Жиль "
@Guilles Этого короткого объяснения достаточно для меня, и я думаю, что оно будет для многих других. Ты за свое время
laconbass
настройка IFSлокально не вступает в силу
Eliran Malka
@EliranMalka Понятия не имею, что вы подразумеваете под этим. Если сценарий ведет себя не так, как вы думаете, вы можете задать вопрос здесь.
Жиль "ТАК - перестань быть злым"
4

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

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

Выше сказано заменить один или несколько пробельных символов (\ s +) символом новой строки (\ n)

Это более или менее:

'substitute /one space or more/ for /newline/ globally'
MGP
источник
1
замените замену заменой, вот что на самом деле означает s!
Роб
@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нет.

FranMowinckel
источник
0

Вот как я это сделал:

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

Обратите внимание на использование клавиши Enter после обратной косой черты в sedкоманде.

unxnut
источник
какие плюсы и минусы sedзакончились tr?
Laconbass
Ваш уровень комфорта :-) Я думаю, вы можете сделать больше с sedпомощью редактора, а не просто переводить символы.
unxnut
4
sedможет сделать гораздо больше, но это совершенно излишне. trэто правильный инструмент для этой работы, но знание sedи регулярные выражения наверняка пригодятся позже!
Роб
0

Другой подход, предполагая, что строка находится в переменной с именем line:

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

Это использует тот факт, что Bash разделяет свои аргументы по пробелам по умолчанию, и это echoдобавляет новую строку к его вводу по умолчанию.

Джозеф Р.
источник
Я попытался сделать это в своей системе Ubuntu, прежде чем опубликовать этот вопрос и не смог заставить его работать.
Laconbass
0
echo word1 word2 ... | sed -e 'y/ /\n/;P;D'

это еще один метод для преобразования слов, разделенных пробелом, в символ новой строки.


источник
-1

Следующий скрипт прост в понимании и использовании.

cat filename | tr ' ' '\n' | tee filename
санджив канабарги
источник
2
Суть вашего ответа ( tr) такая же, как и в принятом ответе. Кроме того, у вашего ответа есть следующие проблемы: a) команда не имеет отступа в 4 пробела (-> разметка уценки) b) использование catвами бесполезно (вы можете заменить его на < filename tr ' ' '\n'). c) Ваше имя файла вывода совпадает с именем файла ввода. С этим вы создаете гонку данных.
maxschlepzig
1
Помимо правильного анализа maxschlepzig, это не сценарий, а набор связанных команд, которые имеют жестко заданное имя (поскольку сценарий, вероятно, будет иметь заголовок, определяющий оболочку, которую нужно использовать, и использовать два параметра для указания и вывода). Кроме того, 2 из 3 человек в моей семье не легко понять. Возможно, это не является репрезентативным, но имейте в виду, что то, что вы сами понимаете (или в этом случае думаете, что понимаете), всегда кажется легким.
Антон