bash - zamień spację na nową linię

70

Jak mogę zastąpić spacje nowymi wierszami na danych wejściowych, takimi jak:

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

Aby uzyskać następujące informacje:

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

Uwaga

Zadaję to pytanie, aby pomóc innym użytkownikom. Znalezienie użytecznej odpowiedzi w UNIX SE nie było łatwe, dopóki nie zacząłem pisać tego pytania. Potem znalazłem następujące:

Powiązane pytanie

Jak mogę znaleźć i zastąpić nową linią?

laconbass
źródło
ls / path / to / | xargs echo | sed 's / \ s \ + / \ n / g'
SD.

Odpowiedzi:

125

Użyj trpolecenia

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

Znalezione na http://www.unix.com/shell-programming-scripting/67831-replace-space-new-line.html

laconbass
źródło
1
tr było również moją pierwszą myślą, chociaż istnieje tak wiele sposobów, aby to zrobić! Jest to jednak DOKŁADNIE po co tr!
Rob
5
+1, ale jako komentarz: To nie działa, jeśli same nazwy plików zawierają spacje
Bonsi Scott,
20

W takim przypadku użyłbym printf:

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

Jeśli w jednej ze ścieżek znajdują się spacje , możesz zacytować tę ścieżkę pliku, aby zapobiec jej podziałowi na spacje:

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

Przekształcanie tekstu trjest najlepszym rozwiązaniem, o czym mowa w istniejącej odpowiedzi.

zła
źródło
1
Krótka uwaga z przyszłości: dzięki za opublikowanie tego rozwiązania, jest ono dla mnie bardzo niezawodne w porównaniu do używania „echa”.
Liesmith,
5

Zakładając, że masz ciąg znaków ze spacjami jako separatorami:

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

Jednak prawdopodobnie zadajesz złe pytanie. (Niekoniecznie, na przykład może pojawić się w pliku makefile). Rozdzielona spacjami lista nazw plików tak naprawdę nie działa: co jeśli jedna z nazw plików zawiera spacje?

Jeśli program otrzymuje nazwy plików jako argumenty, nie łącz ich ze spacjami. Użyj, "$@"aby uzyskać do nich dostęp jeden po drugim. Chociaż echo "$@"drukuje argumenty ze spacjami pomiędzy nimi, wynika to z echo: drukuje argumenty ze spacjami jako separatory. somecommand "$@"przekazuje nazwy plików jako osobne argumenty do polecenia. Jeśli chcesz wydrukować argumenty w osobnych wierszach, możesz użyć

printf '%s\n' "$@"

Jeśli masz nazwy plików rozdzielone spacjami i chcesz umieścić je w tablicy, aby nad nimi pracować, możesz użyć niecytowanego rozszerzenia zmiennej, aby podzielić wartość na znaki IFS(musisz wyłączyć interpretację symboli wieloznacznych za pomocą set -f, w przeciwnym razie glob wzory zostaną rozszerzone o wartość):

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 

Możesz zawrzeć to w funkcji, która przywraca -fustawienie i wartość, IFSkiedy to nastąpi:

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 
Gilles
źródło
Zmiana poprawnej odpowiedzi na to. Myślę, że bardziej poprawne jest zbadanie, w jaki sposób dotarłem do listy rozdzielonej spacjami i odzyskanie tej informacji w inny sposób. Byłoby fajnie dla uczniów takich jak ja, jeśli skomentujesz trochę swój snipnet, mówiąc nam, co robią takie rzeczy, jak lokalny var IFS lub warunek $ - = f do zrobienia. Tego nie wie osoba, która kilka razy używa bashu.
laconbass,
@laconbass Dodałem krótkie wyjaśnienie. Spójrz w górę set -fiw IFSinstrukcji bash, jeśli chcesz wszystkie szczegóły. Zobacz także unix.stackexchange.com/questions/16192/…
Gilles
@Guilles To krótkie wyjaśnienie mi wystarcza i myślę, że będzie dla wielu innych. Ty na twój czas
laconbass
ustawienie IFSlokalne nie ma zastosowania
Eliran Malka
@EliranMalka Nie mam pojęcia, co przez to rozumiesz. Jeśli skrypt nie zachowuje się tak, jak powinien, możesz zadać pytanie tutaj.
Gilles
4

Bądź pragmatyczny, użyj sed !!

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

Powyższe mówi, aby zastąpić jeden lub więcej białych znaków (\ s +) znakiem nowej linii (\ n)

To mniej więcej:

'substitute /one space or more/ for /newline/ globally'
MGP
źródło
1
zamień zmianę na substytut, tak naprawdę oznacza to s!
Rob
@Rob dzięki, pamiętaj, że możesz edytować odpowiedzi innych.
MGP,
1
Jeśli masz wiele spacji między tekstem, otrzymasz puste linie. Musisz dodać znak „+” po \ s, aby wskazać, że chcesz dopasować co najmniej jedną spację w stosunku do dokładnie jednej spacji. to znaczy. sed 's / \ s + / \ n / g'
DarkHeart
4

Jako alternatywę dla tr@laconbass możesz również użyć xargsw tym przypadku:

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

Zaletą jest to, że działa nawet z wieloma białymi spacjami, co trnie działa.

FranMowinckel
źródło
0

Oto jak to zrobiłem:

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

Zwróć uwagę na użycie klawisza Enter po ukośniku odwrotnym w sedpoleceniu.

unxnut
źródło
Wady i zalety jakie posiada sedponad tr?
laconbass
Twój poziom komfortu :-) Myślę, że możesz zrobić więcej, sedponieważ jest to edytor niż zwykłe tłumaczenie znaków.
unxnut
4
sedmoże zrobić o wiele więcej, ale jest to całkowicie przesada. trjest właściwym narzędziem do tej pracy, ale wiedza sedi wyrażenia regularne z pewnością przydadzą się później!
Rob
0

Inne podejście, zakładając, że linia znajduje się w zmiennej o nazwie line:

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

Wykorzystuje to fakt, że Bash domyślnie dzieli argumenty na białe znaki i domyślnie echodołącza nowy wiersz do swoich danych wejściowych.

Joseph R.
źródło
Próbowałem tego na moim systemie Ubuntu, zanim opublikowałem to pytanie i nie mogłem go uruchomić.
laconbass
0
echo word1 word2 ... | sed -e 'y/ /\n/;P;D'

to kolejna metoda zamiany słów oddzielonych spacją na separację nowego wiersza.


źródło
-1

Poniższy skrypt jest łatwy do zrozumienia i łatwy w użyciu.

cat filename | tr ' ' '\n' | tee filename
sanjeev kanabargi
źródło
2
Istota twojej odpowiedzi ( tr) jest taka sama jak w zaakceptowanej odpowiedzi. Poza tym twoja odpowiedź ma następujące problemy: a) polecenie nie jest wcięte 4 spacjami (-> układ znaczników) b) Twoje użycie catjest bezużyteczne (możesz je zastąpić < filename tr ' ' '\n'). c) Twoja wyjściowa nazwa pliku jest taka sama jak wejściowa nazwa pliku. Dzięki temu tworzysz wyścig danych.
maxschlepzig
1
poza poprawną analizą maxschlepzig nie jest to skrypt, ale kilka połączonych poleceń, których nazwa jest zakodowana na stałe (ponieważ skrypt miałby mieć nagłówek określający powłokę do użycia i wykorzystujący dwa parametry do określenia wejścia i wyjścia). Poza tym 2 na 3 osoby w moim domu nie są łatwe do zrozumienia. Może to nie jest reprezentatywne, ale pamiętaj, że coś, co sam rozumiesz (lub w tym przypadku uważasz, że rozumiesz), zawsze wydaje się łatwe.
Anthon