Как печатать простые числа в Bash по заданным аргументам командной строки? [Дубликат]

Вы можете создать редактор настраиваемой коллекции, производящий CollectionEditor, и установить typeof(List<Point>) в качестве типа коллекции, также зарегистрировать новый TypeConverterAttribute для Point:

// Add reference to System.Design
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.ComponentModel.Design;

public class MyPointCollectionEditor : CollectionEditor
{
    public MyPointCollectionEditor() : base(typeof(List<Point>)) { }
    public override object EditValue(ITypeDescriptorContext context,
        IServiceProvider provider, object value)
    {
        TypeDescriptor.AddAttributes(typeof(Point), 
            new Attribute[] { new TypeConverterAttribute() });
        var result = base.EditValue(context, provider, value);
        TypeDescriptor.AddAttributes(typeof(Point), 
            new Attribute[] { new TypeConverterAttribute(typeof(PointConverter)) });
        return result;
    }
}

. Тогда этого достаточно, чтобы зарегистрироваться это как редактор вашего List<Point>:

using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;

public class MyClass : Component
{
    public MyClass() { Points = new List<Point>(); }

    [Editor(typeof(MyPointCollectionEditor), typeof(UITypeEditor))]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public List<Point> Points { get; private set; }
}
1114
задан Peter Mortensen 13 March 2016 в 21:53
поделиться

17 ответов

for i in $(seq 1 $END); do echo $i; done

edit: Я предпочитаю seq по сравнению с другими методами, потому что я действительно могу его запомнить;)

1195
ответ дан Jiaaro 19 August 2018 в 03:52
поделиться
  • 1
    seq включает выполнение внешней команды, которая обычно замедляет работу. Это может быть неважно, но становится важным, если вы пишете скрипт для обработки большого количества данных. – paxdiablo 4 October 2008 в 02:45
  • 2
    Просто отлично подходит для одного лайнера. Решение Pax тоже прекрасно, но если производительность действительно была проблемой, я бы не использовал сценарий оболочки. – eschercycle 4 October 2008 в 02:49
  • 3
    seq вызывается только один раз для генерации чисел. exec () не должно быть значительным, если этот цикл не находится внутри другого жесткого цикла. – Javier 4 October 2008 в 05:40
  • 4
    Внешняя команда не очень релевантна: если вы беспокоитесь о накладных расходах на выполнение внешних команд, вы вообще не хотите использовать сценарии оболочки, но обычно в unix накладные расходы низки. Тем не менее, существует проблема использования памяти, если END высока. – Mark Baker 6 October 2008 в 13:53
  • 5
    Обратите внимание, что seq $END будет достаточным, поскольку по умолчанию должно начинаться с 1. Из man seq: «Если FIRST или INCREMENT опущено, по умолчанию оно равно 1». – fedorqui 5 August 2014 в 10:06

Я знаю, что этот вопрос касается bash, но - только для записи - ksh93 умнее и реализует его, как ожидалось:

$ ksh -c 'i=5; for x in {1..$i}; do echo "$x"; done'
1
2
3
4
5
$ ksh -c 'echo $KSH_VERSION'
Version JM 93u+ 2012-02-29

$ bash -c 'i=5; for x in {1..$i}; do echo "$x"; done'
{1..5}
6
ответ дан Adrian Frühwirth 19 August 2018 в 03:52
поделиться

Если вы выполняете команды оболочки, и у вас (как у I) есть фетиш для конвейерной обработки, это хорошо:

seq 1 $END | xargs -I {} echo {}

3
ответ дан Alex Spangher 19 August 2018 в 03:52
поделиться

Другой слой косвенности:

for i in $(eval echo {1..$END}); do
    ∶
28
ответ дан bobbogo 19 August 2018 в 03:52
поделиться
  • 1
    +1: Также, eval 'для i в {1 ..' $ END '}; do ... 'eval кажется естественным способом решить эту проблему. – William Pursell 14 March 2011 в 21:07

Способ POSIX

Если вы заботитесь о переносимости, используйте пример из стандарта POSIX :

i=2
end=5
while [ $i -le $end ]; do
    echo $i
    i=$(($i+1))
done

Выход:

2
3
4
5

Вещи, которые не POSIX:

161
ответ дан Community 19 August 2018 в 03:52
поделиться
  • 1
    Единственный недостаток цикла цикла C, что он не может использовать аргументы командной строки, поскольку они начинаются с & quot; $ & quot ;. – karatedog 9 January 2012 в 15:15
  • 2
    @karatedog: for ((i=$1;i<=$2;++i)); do echo $i; done в скрипте отлично работает для меня в bash v.4.1.9, поэтому я не вижу проблемы с аргументами командной строки. Вы имеете в виду что-то еще? – tzot 9 January 2012 в 16:41
  • 3
    Кажется, что решение eval быстрее, чем построено в C-like для: $ time for ((i = 1; i & lt; = 100000; ++ i)); делать :; done real 0m21.220s user 0m19.763s sys 0m1.203s $ time для i в $ (eval echo & quot; {1..100000} "); делать :; сделанный; real 0m13.881s пользователь 0m13.536s sys 0m0.152s – Marcin Zaluski 4 July 2012 в 15:55
  • 4
    Да, но eval is evil ... @MarcinZaluski time for i in $(seq 100000); do :; done намного быстрее! – F. Hauri 2 August 2013 в 05:58
  • 5
    Производительность должна быть специфичной для платформы, поскольку версия eval выполняется быстрее всего на моей машине. – Andrew Prock 3 April 2014 в 00:25
  • 6
    На этот ответ было всего 4 upvotes, что очень необычно. Если это было опубликовано на веб-сайте агрегации ссылок, пожалуйста, дайте мне ссылку, приветствия. – Ciro Santilli 新疆改造中心 六四事件 法轮功 4 September 2016 в 19:46
  • 7
    Цитата относится к x, а не ко всему выражению. $((x + 1)) просто отлично. – chepner 14 October 2016 в 12:12
  • 8
    Хотя он не переносимый и отличается от GNU seq (BSD seq позволяет установить строку завершения последовательности с -t), FreeBSD и NetBSD также имеют seq с 9.0 и 3.0 соответственно. – Adrian Günter 23 April 2018 в 18:31
  • 9
    @CiroSantilli @chepner $((x+1)) и $((x + 1)) разыгрываются точно так же, как когда парсер токенизирует x+1, он будет разбит на 3 жетона: x, + и 1. x не является допустимым числовым токеном, но он является допустимым токеном имени переменной, но x+ не является, следовательно, разделенным. + является допустимым токеном арифметического оператора, но +1 не является, поэтому токен снова расщепляется. И так далее. – Adrian Günter 23 April 2018 в 18:37

Вот почему исходное выражение не сработало.

Из man bash :

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

Итак, расширение скобки - это что-то, сделанное раньше, как чисто текстовое макро-операции, до расширения параметра .

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

Рекомендация

Я бы предложил придерживаться Posix1 функции. Это означает использование for i in <list>; do, если список уже известен, в противном случае используйте while или seq, как в:

#!/bin/sh

limit=4

i=1; while [ $i -le $limit ]; do
  echo $i
  i=$(($i + 1))
done
# Or -----------------------
for i in $(seq 1 $limit); do
  echo $i
done

1. Bash - отличная оболочка, и я использую ее в интерактивном режиме , но я не ставил bash-isms в мои скрипты. Скриптам может понадобиться более быстрая оболочка, более безопасная, более встроенная. Им может потребоваться запустить все, что установлено как / bin / sh, и тогда есть все обычные аргументы pro-standards. Помните shellshock, aka bashdoor?

82
ответ дан DigitalRoss 19 August 2018 в 03:52
поделиться
  • 1
    У меня нет власти, но я бы переместил это довольно немного вверх по списку, прежде всего в пушках, но сразу после C-стиля для цикла и арифметической оценки. – mateor 15 March 2013 в 20:03
  • 2
    Подразумевается, что расширение скобок не экономит много памяти по сравнению с seq для больших диапазонов. Например, echo {1..1000000} | wc показывает, что эхо дает 1 строку, миллион слов и 6 888 896 байт. Попытка seq 1 1000000 | wc дает миллион строк, миллион слов и 6 888 896 байт, а также более чем в семь раз быстрее, чем измеряется командой time. – George 19 January 2015 в 02:52
  • 3
    Примечание. Ранее я упомянул метод POSIX while: stackoverflow.com/a/31365662/895245 Но рад, что вы согласитесь :-) – Ciro Santilli 新疆改造中心 六四事件 法轮功 4 September 2016 в 20:09

Это работает в Bash и Korn, также может идти от более высоких к более низким числам. Наверное, не самый быстрый или красивый, но работает достаточно хорошо. Также обрабатывает негативы.

function num_range {
   # Return a range of whole numbers from beginning value to ending value.
   # >>> num_range start end
   # start: Whole number to start with.
   # end: Whole number to end with.
   typeset s e v
   s=${1}
   e=${2}
   if (( ${e} >= ${s} )); then
      v=${s}
      while (( ${v} <= ${e} )); do
         echo ${v}
         ((v=v+1))
      done
   elif (( ${e} < ${s} )); then
      v=${s}
      while (( ${v} >= ${e} )); do
         echo ${v}
         ((v=v-1))
      done
   fi
}

function test_num_range {
   num_range 1 3 | egrep "1|2|3" | assert_lc 3
   num_range 1 3 | head -1 | assert_eq 1
   num_range -1 1 | head -1 | assert_eq "-1"
   num_range 3 1 | egrep "1|2|3" | assert_lc 3
   num_range 3 1 | head -1 | assert_eq 3
   num_range 1 -1 | tail -1 | assert_eq "-1"
}
0
ответ дан Ethan Post 19 August 2018 в 03:52
поделиться

Если вам нужен префикс, который вам может понравиться

 for ((i=7;i<=12;i++)); do echo `printf "%2.0d\n" $i |sed "s/ /0/"`;done

, который даст

07
08
09
10
11
12
11
ответ дан hossbear 19 August 2018 в 03:52
поделиться

Метод seq является самым простым, но у Bash есть встроенная арифметическая оценка.

END=5
for ((i=1;i<=END;i++)); do
    echo $i
done
# ==> outputs 1 2 3 4 5 on separate lines

Конструкция for ((expr1;expr2;expr3)); работает так же, как for (expr1;expr2;expr3) на C и подобных языках, и нравится других ((expr)) случаях, Bash рассматривает их как арифметику.

313
ответ дан icedwater 19 August 2018 в 03:52
поделиться
  • 1
    Человек постоянно учится. Я предпочел бы typeset -i i END. В периоды pre-bash (т. Е. Ksh) это имело значение, но компьютеры были намного медленнее. – tzot 4 October 2008 в 23:59
  • 2
    Этот способ позволяет избежать накладных расходов памяти большого списка и зависимости от seq. Используй это! – bobbogo 14 March 2011 в 21:08
  • 3
    лучшее решение для меня, поскольку мне это нужно для bash на разных ОС – Hachi 2 July 2013 в 09:37
  • 4
    @MarinSagovac Это работает , и нет синтаксических ошибок. Вы уверены, что ваша оболочка Bash? – gniourf_gniourf 13 February 2015 в 13:05
  • 5
    @MarinSagovac Обязательно сделайте #!/bin/bash первую строку вашего скрипта. [Д0] wiki.ubuntu.com/… – Melebius 24 April 2017 в 13:22
  • 6

Это другой способ:

end=5
for i in $(bash -c "echo {1..${end}}"); do echo $i; done
6
ответ дан Jahid 19 August 2018 в 03:52
поделиться

Если вы используете BSD / OS X, вы можете использовать jot вместо seq:

for i in $(jot $END); do echo $i; done
18
ответ дан jefeveizen 19 August 2018 в 03:52
поделиться

Это прекрасно работает в bash:

END=5
i=1 ; while [[ $i -le $END ]] ; do
    echo $i
    ((i = i + 1))
done
13
ответ дан paxdiablo 19 August 2018 в 03:52
поделиться
  • 1
    ((i++)) работает – Dennis Williamson 19 October 2009 в 23:28
  • 2
    echo $((i++)) работает и объединяет его в одну строку. – Bruno Bronosky 30 September 2014 в 05:19
  • 3
    Это имеет ненужные расширения bash. Версия POSIX: stackoverflow.com/a/31365662/895245 – Ciro Santilli 新疆改造中心 六四事件 法轮功 12 July 2015 в 07:55
  • 4
    @Ciro, так как вопрос конкретно указывает bash и имеет тег bash, я думаю, вы, вероятно, обнаружите, что расширения bash более чем в порядке :-) – paxdiablo 12 July 2015 в 08:29
  • 5
    @paxdiablo Я не имею в виду, что это неправильно, но почему бы не быть переносимым, когда мы можем ;-) – Ciro Santilli 新疆改造中心 六四事件 法轮功 12 July 2015 в 08:39

Вы можете использовать

for i in $(seq $END); do echo $i; done
21
ответ дан Peter Hoffmann 19 August 2018 в 03:52
поделиться
  • 1
    Это не связано с выполнением внешней команды для каждой итерации только один раз. Если время запуска одной внешней команды является проблемой, вы используете неправильный язык. – Mark Baker 6 October 2008 в 13:57
  • 2
    +1 для $() вместо backticks – Dennis Williamson 19 October 2009 в 23:27
  • 3
    Почему $ () лучше, чем ``? – Sqeaky 18 October 2011 в 19:19
  • 4
    @Sqeaky: вы когда-нибудь пытались вложить вызовы ``? -) – tzot 9 January 2012 в 16:45
  • 5
    Так что же гнездование - единственный случай, когда это имеет значение? Мне было интересно, есть ли разница в производительности или какой-то неизвестный технический побочный эффект? – Sqeaky 9 January 2012 в 21:07

Все это хорошо, но seq предположительно устарел, и большинство из них работают только с числовыми диапазонами.

Если вы заключите цикл for в двойные кавычки, стартовые и конечные переменные будут разыменованы, когда вы будете эхо-строки , и вы можете отправить строку обратно в BASH для выполнения. $i должен быть экранирован, поэтому он НЕ оценивается перед отправкой на подоболочку.

RANGE_START=a
RANGE_END=z
echo -e "for i in {$RANGE_START..$RANGE_END}; do echo \\${i}; done" | bash

Этот вывод также может быть назначен переменной:

VAR=`echo -e "for i in {$RANGE_START..$RANGE_END}; do echo \\${i}; done" | bash`

Единственный «служебный» ресурс, который должен генерировать, должен быть вторым экземпляром bash, поэтому он должен быть подходящим для интенсивных операций.

4
ответ дан sjngm 19 August 2018 в 03:52
поделиться

Заменить {} на (( )):

tmpstart=0;
tmpend=4;

for (( i=$tmpstart; i<=$tmpend; i++ )) ; do 
echo $i ;
done

Выход:

0
1
2
3
4
4
ответ дан sth 19 August 2018 в 03:52
поделиться

Если вы хотите как можно ближе подойти к синтаксису выражения, попробуйте функцию range из bash-трюков range.bash .

Для Например, все следующие будут делать то же самое, что и echo {1..10}:

source range.bash
one=1
ten=10

range {$one..$ten}
range $one $ten
range {1..$ten}
range {1..10}

Он пытается поддерживать собственный синтаксис bash с максимально возможным количеством «gotchas»: поддерживаются не только переменные, но часто нежелательное поведение недопустимых диапазонов, предоставляемых как строки (например, for i in {1..a}; do echo $i; done), также предотвращается.

Другие ответы будут работать в большинстве случаев, но все они имеют по крайней мере одно из следующих Недостатки:

  • Многие из них используют подоболочки , что может снизить производительность и , возможно, невозможно на некоторых систем.
  • Многие из них полагаются на внешние программы. Даже seq представляет собой двоичный файл, который должен быть установлен для использования, должен быть загружен bash и должен содержать ожидаемую программу, чтобы он работал в этом случае.
  • Решения, которые используют только собственные функции Bash, такие как @ ephemient, не будут работать в алфавитном диапазоне, например {a..z}; расширение скобки будет. Вопрос был о диапазонах номеров , хотя это так.
  • Большинство из них не визуально похожи на синтаксис диапазона расширенного набора {1..10}, поэтому программы, которые используют оба варианта, могут быть немного труднее читать.
  • @ Ответ bobbogo использует некоторый знакомый синтаксис, но делает что-то неожиданное, если переменная $END не является допустимым диапазоном «bookend» для другая сторона диапазона. Если END=a, например, ошибка не будет выполнена, и будет передано дословное значение {1..a}. Это также поведение Bash по умолчанию - это просто неожиданно.

Отказ от ответственности: я являюсь автором связанного кода.

2
ответ дан Zac B 19 August 2018 в 03:52
поделиться
162
ответ дан Community 30 October 2018 в 15:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: