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ą?



ls / path / to / | xargs echo | sed 's / \ s \ + / \ n / g'
SD.

Odpowiedzi:



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.


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 

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'

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.


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.


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.


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.


-1

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

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

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.