Bash - Послідовність чисел в одному рядку


20

Я знаю команду seqдля генерування послідовності цілих чисел, по одному на рядок, але я хотів би задати два питання:

  1. Чи можна записати числа послідовності в одному рядку?

  2. Чи можливо створити рядок з послідовності чисел, розділених пробілом?


Оболонка розглядає нові рядки, як пробіли, як роздільники аргументів. Отже, поки seq має аргумент роздільника, і навіть простіше сказати простоecho $(seq 1 10)
user3188445

1
@ user3188445, це робить оператор split + glob (який використовує спеціальну змінну IFS, яка за замовчуванням містить пробіл та новий рядок, але може бути змінена), це окремо від токенізації слова, виконаної оболонкою.
Стефан Шазелас

Відповіді:



21

GNU seqприймає -sопцію separator ( ):

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

$ var="$(seq -s ' ' 1 5)"
$ echo "$var"
1 2 3 4 5

1
echo $(seq 5)працює чудово.

13

Переносний для всіх оболонок та будь-якої системи, що має послідовність (як зазначені питання, позначені тегами)

Якщо старт 1:

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

Інакше:

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

З bc:

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

В баш

echo {1..10}

Примітка:

Це рішення ехо працює, якщо значення IFS містить новий рядок, який він робить за замовчуванням.
За замовчуванням IFS встановлюється в послідовності <space><tab> <newline> . І скидається для кожного чистого запуску оболонки. Але якщо у вас є занепокоєння, що це могло змінитися в якомусь крайньому кутовому випадку, у нас є кілька рішень.

Під bash, zsh, ksh просто використовуйте: IFS = $ '\ t \ n' (пропустіть всю решту цієї відповіді).


Однак скидання значення IFS під sh може бути складним. Прочитайте повну деталь тут .

Вимкнути IFS.

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

завжди працюватиме. За умови, що внизу не буде коду (або дочірніх сценаріїв), який потребує встановлення IFS, наприклад, сценарій, який це робить OldIFS="$IFS".

Правильне рішення.

Використання хитрості для sh:

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

Коментарі не для розширеного обговорення; ця розмова переміщена до чату .
terdon

1
Більшість реалізацій sh ігнорують IFS, що знаходяться в оточенні (виняток становлять деякі похідні золи, дуже старі версії деяких оболонок Bourne та останні версії posh). Зверніть увагу , що ви можете просто зробити , IFS='<space><tab><newline>' де ті <space>, <tab>, <newline>є відповідні буквальні символи.
Стефан Шазелас


0
seq 10 |xargs

... або ...

seq 10 |paste -s -

Обидві команди, наведені вище, будуть розділяти цілі числа на пробіл. xargsза замовчуванням наслідує /bin/echoі тому кожне ціле число відокремлено одним пробілом. Тим не менше, макс. Довжина командного рядка - 128 К. Ви можете налаштувати це ...

seq 100000 | xargs -s2093009 | wc -l

... друкує 1. Я для цього значення -sне довільний - я отримав це після спробу більш високого значення (яке, мабуть, все одно працювало), але потім xargsнадрукував корисне повідомлення:

-s value should be <2093010

pasteє однією з двох (наскільки мені відомо), санкціонованих POSIX утиліт для обробки ліній довільної довжини:

pasteвикористання програми специфікації :

Більшість стандартних утиліт працюють над текстовими файлами . cutУтиліта може бути використана , щоб перетворити файли з довільною довжиною рядка в набір текстових файлів , що містять одні і ті ж дані. pasteУтиліта може бути використана для створення (або відтворювати) файли з довільною довжиною рядка.

текстові файли

Файл, який містить символи, впорядковані в нуль або більше рядків. Рядки не містять символів NUL і жодна {LINE_MAX}довжина не може перевищувати байт, включаючи \nсимвол ewline. Хоча POSIX.1-2008 не розрізняє текстові файли та бінарні файли (див. Стандарт ISO C) , багато утиліт виробляють передбачуваний або значущий вихід під час роботи з текстовими файлами. Стандартні утиліти, які мають такі обмеження, завжди вказують текстові файли у своїх розділах STDIN або INPUT FILES .

pasteза замовчуванням для роздільника вкладок, і тому буде вкладено кожне ціле число за другою командою. Ти можеш...

seq 10 |paste -sd ' ' - 

... використовувати -dперемикач елімінатора, щоб змінити таку поведінку,


seq 10 | xargsпрацює чудово, але через обмеження командного рядка seq 100000 | xargsвиводить 5 \nобмежених рядків (у моїй системі)
Peter.O

@ Peter.O - paste and cut` - це дві санкціоновані утиліти POSIX для роботи з лініями арбітражної довжини. Це сказав xargs | xargs- варіант. Або щеseq 100000|tr \\n \
mikeserv

Коментарі не для розширеного обговорення; ця розмова переміщена до чату .
terdon

@BinaryZebra - ні, ні - не так, як ти думаєш, це робить. Чому б не спробувати встановити $IFSчисло? І в bashйого побожному повільному все одно. У своїй відповіді, про яку ви говорите sh- вам навіть не потрібно встановлювати $IFSв цьому контексті - вона буде передана через середовище, якщо вона встановлена ​​там. І це не коротше, ніж seq 100000|paste -sце перемагає 5: 1. І pasteне приходить з жодними дітьми.
mikeserv

@BinaryZebra - давай, чому я б брехав? Чи є у мене на цьому сайті великий профіль відповідей, оскільки мені подобається поширення дезінформації? А може, це тому, що мені подобається допомагати людям і насолоджуватися завданням навчання, поки я роблю? Як ви вважаєте, що є більш правдоподібним? Мені подобається $IFS- я користуюся ним постійно - але я не користуюся ним, якщо не встановив його, а також не слід. Тим більше не слід рекомендувати випадковим незнайомцям, які не знають кращого, ніж це робити. Не залишайте це випадковістю - це комп'ютерна програма. Це помилка, якщо вона поводиться несподівано - навіщо допускати, що це може?
mikeserv
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.