Bash - Sekwencja liczb w tej samej linii

20

Znam polecenie seqgenerowania sekwencji liczb całkowitych, po jednym w wierszu, ale chciałbym zadać dwa pytania:

  1. Czy możliwe jest zapisanie liczb sekwencji w tym samym wierszu?

  2. Czy można utworzyć ciąg złożony z sekwencji liczb oddzielonych białą spacją?

Salsiccio
źródło
Powłoka traktuje znaki nowej linii jak spacje jako separatory argumentów. Tak więc, podczas gdy seq ma argument separatora, a jeszcze prostsze do powiedzenia jest tylkoecho $(seq 1 10)
user3188445
1
@ użytkownik3188445, robi to operator split + glob (który korzysta ze specjalnej zmiennej IFS, która domyślnie zawiera spację i znak nowej linii, ale może być zmieniona), jest niezależna od tokenizacji słowa wykonywanej przez powłokę.
Stéphane Chazelas

Odpowiedzi:

21

GNU seqprzyjmuje -sopcję separatora ( ):

$ seq -s ' ' 1 5
1 2 3 4 5

$ var="$(seq -s ' ' 1 5)"
$ echo "$var"
1 2 3 4 5
heemayl
źródło
1
echo $(seq 5)działa w porządku.
13

Przenośny dla wszystkich powłok i każdego systemu, który ma sekwencję (ponieważ to pytanie jest oznaczone)

Jeśli start to 1:

$ echo $(seq 10)
1 2 3 4 5 6 7 8 9 10

Inaczej:

$ echo $(seq 5 10)
5 6 7 8 9 10

Z bc:

$ echo $(echo "for (i=0;i<=1000;i++) i"| bc)

W bash

echo {1..10}

Uwaga:

To rozwiązanie echa działa, jeśli wartość IFS zawiera nową linię, co robi domyślnie.
Domyślnie IFS jest ustawione na sekwencję <space><tab> <newline> . I jest resetowany dla każdego czystego początku powłoki. Ale jeśli masz obawy, że mogło się to zmienić w skrajnym przypadku, mamy kilka rozwiązań.

W bash, zsh, ksh po prostu użyj: IFS = $ '\ t \ n' (pomiń resztę tej odpowiedzi).


Jednak resetowanie wartości IFS pod sh może być skomplikowane. Przeczytaj pełny szczegół tutaj .

Unset IFS.

$ unset IFS; echo $(seq 5 10)                           #Always work.

zawsze będzie działać. Pod warunkiem, że poniżej nie będzie kodu (lub skryptów potomnych), które wymagałyby ustawienia IFS, takiego jak skrypt, który to robi OldIFS="$IFS".

Prawidłowe rozwiązanie

Używanie sztuczki dla sh:

sh -c 'IFS="$(printf " \t\nx")"; IFS="${IFS%x}"; printf "$IFS"|xxd'  # correct.

źródło
Komentarze nie są przeznaczone do rozszerzonej dyskusji; ta rozmowa została przeniesiona do czatu .
terdon
1
Większość implementacji sh zignoruje IFS znalezione w środowisku (wyjątkami są niektóre pochodne popiołu, bardzo stare wersje niektórych powłok Bourne'a i najnowsze wersje posh). Należy pamiętać, że można po prostu zrobić IFS='<space><tab><newline>' , gdzie ci <space>, <tab>, <newline>są odpowiednie znaki dosłowne.
Stéphane Chazelas
3

Użyj tego:

string="$(seq -s " " 1 10)"
Cyrus
źródło
0
seq 10 |xargs

...lub...

seq 10 |paste -s -

Oba powyższe polecenia oddzielą liczby całkowite spacjami. xargsdomyślnie imituje, /bin/echowięc każda liczba całkowita jest oddzielona pojedynczą spacją. Domyślnie maksymalna długość wiersza poleceń wynosi 128 KB. Możesz to dostosować ...

seq 100000 | xargs -s2093009 | wc -l

... drukuje 1. I wartość -stutaj nie jest arbitralna - otrzymałem ją po wypróbowaniu wyższej wartości (która najwyraźniej i tak działała), ale potem xargswydrukowałem pomocny komunikat:

-s value should be <2093010

pastejest jednym z dwóch (o ile mi wiadomo) sankcjonowanych przez POSIX narzędzi do obsługi linii o dowolnej długości:

pasteużycie aplikacji specyfikacji :

Większość standardowych narzędzi działa na plikach tekstowych . Za pomocą tego cutnarzędzia można zamienić pliki o dowolnej długości linii na zestaw plików tekstowych zawierających te same dane. pasteNarzędzie może być wykorzystywane do tworzenia (i tworzenia) plików z dowolnych długościach linii.

pliki tekstowe

Plik zawierający znaki zorganizowane w zero lub więcej wierszy. Linie nie zawierają znaków NUL i żaden z nich nie może przekraczać {LINE_MAX}długości bajtów, w tym \nznaku ewline. Chociaż POSIX.1-2008 nie rozróżnia plików tekstowych od plików binarnych (patrz standard ISO C) , wiele programów narzędziowych generuje przewidywalne lub znaczące dane wyjściowe podczas pracy na plikach tekstowych. Standardowe narzędzia, które mają takie ograniczenia, zawsze określają pliki tekstowe w swoich sekcjach STDIN lub INPUT FILES .

pastedomyślnie jest to separator tabulatorów, więc między kolejnymi liczbami po drugiej komendzie będzie tabulator. Możesz...

seq 10 |paste -sd ' ' - 

... użyj -dprzełącznika eliminatora, aby zmienić to zachowanie,

mikeserv
źródło
seq 10 | xargsdziała dobrze, ale z powodu ograniczeń wiersza poleceń, seq 100000 | xargswypisuje 5 \nlinii rozdzielanych (w moim systemie)
Peter.O
@ Peter.O - paste and cut` to dwa zatwierdzone narzędzia POSIX do pracy z liniami o dowolnej długości. To powiedziawszy, xargs | xargsjest opcją. Albo inaczejseq 100000|tr \\n \
mikeserv
Komentarze nie są przeznaczone do rozszerzonej dyskusji; ta rozmowa została przeniesiona do czatu .
terdon
@BinaryZebra - nie, nie ma - nie tak, jak myślisz. Dlaczego nie spróbować ustawić $IFSnumer? A w bashjego godawful zwolnionym tak. W odpowiedzi, o której mówisz sh- nie musisz nawet ustawiać $IFSw tym kontekście - zostanie przekazany przez środowisko, jeśli jest tam ustawiony. I nie jest krótszy niż ten, seq 100000|paste -sktóry bije go pod względem wydajności 5: 1. I pastenie wchodzi w żadne gotchas.
mikeserv
@BinaryZebra - daj spokój, dlaczego miałbym kłamać? Czy mam duży profil odpowiedzi na tej stronie, ponieważ lubię rozpowszechniać dezinformacje? A może dlatego, że lubię pomagać ludziom i czerpać radość z nauki, kiedy to robię? Jak myślisz, co jest bardziej prawdopodobne? I jak $IFS- używam go cały czas - ale nie używam go chyba ja ustawić go i ani zalecana. Szczególnie nie powinieneś polecać przypadkowym nieznajomym, którzy nie wiedzą nic lepszego, powinni to zrobić. Nie pozostawiaj tego przypadkowi - to program komputerowy. To błąd, jeśli zachowuje się nieoczekiwanie - po co na to pozwolić?
mikeserv