Как сделать mksh для цикла перейдите от 1 к N

Поэтому я попытался сделать это

for x in {1..7000} do echo $x done 

Вывод: {1..7000}

Я также узнал, что цикл цикла C не работает в mksh

Я сделал немного поиска, но в основном есть информация о ksh, а не mksh

Итак, каков правильный способ повторения диапазона в mksh?

ПРИМЕЧАНИЕ. Меня больше интересует правильный способ создания итераций и c-подобного поведения, а не для печати строки.

One Solution collect form web for “Как сделать mksh для цикла перейдите от 1 к N”

Итак, в первую очередь, как кратко обсуждается здесь общая форма …

 for arg in {brace..expanded..set}; do ... 

… является, на мой взгляд, образцовой ошибкой программирования оболочки. Он генерирует формульный набор в цикле, сохраняет каждый результат в разделительном массиве, затем передает другой цикл указанному массиву как список, по которому выполняется итерация.

Как правило, расширение скобок не особенно полезно в контексте программирования, потому что все программирование оболочки так или иначе похоже на макроподобное, а расширение фигурной скобки уже является макросом . Хотя расширение брекетов (также, на мой взгляд) очень полезно для интерактивной оболочки, именно потому, что это макрос, в противном случае это может быть расточительно.

Расширение брекетов также не переносимо (читайте: POSIX-портативный) . Насколько я знаю, вы можете полагаться на него, чтобы работать в текущих версиях zsh , bash , ksh93 и ksh93 но не в другом месте. И даже в этих оболочках его можно отключить с помощью параметров оболочки, и поэтому в контексте оболочки нельзя определенно полагаться, хотя его доступность обычно может быть протестирована в $- или на выходе set +o . Между ними каждая из вышеупомянутых оболочек потребует разных типов тестов, поэтому, если вы планируете использовать ее в функции и хотите протестировать ее, проверьте ее руководство по конкретным командам.

В других оболочках вы можете получить практически одно и то же поведение, за исключением того, что для генерации набора необходимо вызывать внешний исполняемый файл, разделяя вывод команды-подстановки на $IFS . Там, где доступна программа seq это легко продемонстрировать, как …

 unset IFS ### ^ensure $IFS default behavior for arg in $(seq 7000) do printf %d\\n "$arg" done 

…или…

 unset IFS printf %d\\n $(seq 7000) 

… но, как написано, не предлагает ничего, кроме недостатка …

 seq 7000 

Тем не менее – для первого примера – метод почти такой же, как и расширенная версия. В обоих случаях какая-то другая функция или процесс генерирует полный список аргументов, которые затем обрабатывают конструкцию управления. Однако в последнем случае (для оболочек, отличных от ksh93 ) есть также дополнительные накладные расходы на открытие / отрыв трубы, процесс раздвоенной оболочки и его дочерний процесс seq , а также последняя работа по разбиению его вывода на $IFS .

$IFS расщепление, кстати, происходит на очень разных скоростях в зависимости от используемой оболочки. Например, bash , как правило, ужасен при простом расщеплении $IFS , тогда как dash – в зависимости от длины строки для разделенных строк – часто можно делать это так же быстро, как некоторые другие оболочки расширяют брекеты.

Если вы используете расщепление расширений или расщепление $IFS , конечный результат заключается в том, что вы будете запускать некоторый цикл для создания формульного списка, а затем другого для повторения этого списка. То, что вы могли бы – и, вероятно, должно было бы сделать – вместо этого, выполняло единый цикл над приложением формулы, которая генерирует список, удаляет использованные итераторы, как только это возможно, и проверяет результат каждой из каждой итерации для удовлетворительный результат. Это то, что вы бы сделали в C, как …

 for ( x = 0; x < 10; x++ ){ ... 

Это также практически тот же синтаксис, который вы можете использовать в bc . И это очень похоже на формы удобного синтаксиса, которые могут быть использованы в ksh93 , zsh или bash например:

 for (( x=0; x<10; x++ )); do ... 

Это, однако, также не переносимо (опять же, прочитайте: POSIX) . Вместо этого вы можете сделать это:

 iterator=$(( start_value - interval )) while [ "$(( iterator += interval ))" -le "$end_value" ]; do ... 

…или…

 iterator=$(( start_value - interval )) while [ "$(( ( iterator += interval ) <= end_value ))" -ne 0 ]; do ... 

POSIX указывает что-то близкое к четности функции для арифметических расширений оболочки и арифметических операций на языке C – где целые числа, то есть. И поэтому вы часто можете удобно и переносимо перебирать даже сложные формулы только с одним расширением – и может даже перебирать несколько переменных одновременно синхронно.

С другой стороны, такая конструкция, скорее всего, приведет вас к еще большему противоречию с другим языком языка C и оболочкой. Shell читает и пишет почти всегда буквально read() s и write() s – каждый из них – syscall для себя – и в синтаксисе оболочки нет портативных аналогов для fread() , fwrite() и / или setbuf() . И поэтому любой цикл, который выполняет любой из этих видов операций на итерацию, даже когда он делает это только со встроенными, неизбежно приводит к производительности собаки.

Тем не менее, вы иногда можете достичь счастливой среды между генерацией и работой всего набора в серии или в параллели в сценарии оболочки.

 set 0 1 2 3 4 5 6 7 8 9 for n do printf "$n%d\n" "$@"; done 

Это делает десять write() s в десяти итерациях и печатает новую последовательность разделенных строк от 00 до 99. Это крошечный пример – и все еще расточительный, поскольку 30-байтная write() вряд ли является значительным улучшением по сравнению с 3-байтной write() но это демонстрирует тот способ, который вы можете использовать. Как я уже упоминал ранее, язык программирования оболочки очень похож на макрос, поскольку все это строка . И поэтому, если вы можете сломать свою цель, поставленную на более мелкие, более управляемые наборы, а затем многократно называть их в контексте цикла, чтобы в конечном итоге создать набор ваших целей, вы обычно можете получить более результативный результат.

Вот более сложный, похожий на макрос пример:

 sh -c ' i=0 _i=-25 set "$1" "$1" "$1" "$1" "$1" for n do eval " printf %b%d $@ $@ $@ $@ $@" done' -- \ '"\01$((1+(i<(i+=!(_i=(_i+=25)%275)))))" "$i$_i"' 

Который итерации 5 раз для одной write() – в среднем – около 100 байт в секунду и отпечатков:

 10 125 150 175 1100 1125 1150 1175 1200 1225 1250 20 225 250 275 2100 2125 2150 2175 2200 2225 2250 30 325 350 375 3100 3125 3150 3175 3200 3225 3250 40 425 450 475 4100 4125 4150 4175 4200 4225 4250 50 525 550 575 5100 5125 5150 5175 5200 5225 5250 60 625 650 675 6100 6125 6150 6175 6200 6225 6250 70 725 750 775 7100 7125 7150 7175 7200 7225 7250 80 825 850 875 8100 8125 8150 8175 8200 8225 8250 90 925 950 975 9100 9125 9150 9175 9200 9225 9250 100 1025 1050 1075 10100 10125 10150 10175 10200 10225 10250 110 1125 1150 1175 11100 11125 11150 11175 11200 11225 11250 120 1225 1250 1275 
Interesting Posts

Как загрузить часть видео с помощью команды youtube-dl?

Рекомендуемый способ переупаковки собственных пакетов deb, которые включают старые системные библиотеки

Заставить пользователя создать 775 папок разрешений

Что является преимуществом (-ами) запуска приложений в backgound?

GUFW или Firestarter в Fedora

Настройка переменных среды с .sh-файлом

Настройка входа в виртуальную машину вместо локального входа

Прямой дистрибутив Linux с предустановленной поддержкой NVIDIA CUDA

Создать точку монтирования и смонтировать блочное устройство с помощью одной команды?

Отображать номера в метрах htop

Ошибки внутреннего сервера с CUPS

Почему существуют два последовательных процесса экрана?

Как я могу вырезать видео из линейного сегмента с помощью ffmpeg?

fail2ban отлично работает при неудачных попытках SSH, но не работает при неудачных попытках Apache2

Как найти окончательный сертификат CA в действительном сертификате

Linux и Unix - лучшая ОС в мире.