2016-02-04 2 views
2

Это очень простой скрипт, но я не могу понять, что это правильно. Этот код должен печатать IP-адреса класса C с 192.168.0.0 - 192.168.255.255, но все, что печатает, - 192.168.0.0 - 192.168.0.255. По какой-то причине мой внешний цикл не будет зацикливаться. Я уверен, что это что-то глупое, но это может быть полезно для тех людей, которые учатся вложенным циклам в сценариях оболочки. Любые другие советы приветствуются!Beginner Shell Scripting - вложенный цикл while, внутренний цикл - это только цикл цикла

#! /bin/sh 
network_id="192.168." 
count1=-1 
count2=-1 
while [ "$count1" -le 254 ] 
do 
    count1=$(($count1+1)) 
    while [ "$count2" -le 254 ] 
    do 
     count2=$(($count2+1)) 
     printf "%s%s%s%s\n" $network_id $count1 "." $count2 
    done 
done 
exit 0 
+2

Обратите внимание, что '' '' не требуется внутри конструкции с двойными скобками. Например. '$ ((count1 + 1))' работает отлично. – vastlysuperiorman

+1

Обратите внимание, что при запуске скриптов в режиме совместимости POSIX с использованием '#!/Bin/sh', это означает, что они будут переносимыми. В ответе ниже предлагается использовать '{0..255}'. В то время как BASH будет расширяться, другие реализации POSIX/bin/sh, вероятно, не будут. Если вы пишете для bash, лучше использовать '#!/Usr/bin/env bash' как ваш shebang. Если вы пишете для переносимости, лучше не использовать багизмы. – ghoti

+0

Интригует, что первые два цикла 'while' отвечают на сброс' count2' после завершения внутреннего 'while'. Я бы установил его до того, как он запустится (и не до начала внешнего цикла). Но обе техники достигают того же результата. –

ответ

2

Вы не обнуляете count2. Ваш внешний цикл работает 256 раз, но внутренний цикл останавливается после однократного запуска.

Если вы добавите count2=-1 после закрытия внутреннего контура, он будет работать должным образом.

Для ясности я бы переместил ваш приращение, чтобы вы четко повторялись между 0-255. Вот как я бы это написал:

#! /bin/sh 
network_id="192.168." 
count1=0 
count2=0 
while [ "$count1" -le 255 ]; do 
    while [ "$count2" -le 255 ]; do 
     printf "%s%s%s%s\n" $network_id $count1 "." $count2 
     count2=$(($count2+1)) 
    done 
    count2=0 
    count1=$(($count1+1)) 
done 
+1

Вау, я знал, что это что-то в этом роде. Это просто программа, даже не скриптовая сценария. Я чувствую себя немой, но спасибо! – Colin93

+1

@ Colin93 Пожалуйста, не забудьте выбрать это как правильный ответ, если он решит вашу проблему. :) – vastlysuperiorman

2

Ничего, кроме небольшой ошибки. Вы didnot набор $count=-1

#! /bin/sh 
network_id="192.168." 
count1=-1 
count2=-1 
while [ "$count1" -le 254 ] 
do 
    count1=$(($count1+1)) 
    while [ "$count2" -le 254 ] 
    do 
     count2=$(($count2+1)) 
     printf "%s%s%s%s\n" $network_id $count1 "." $count2 
    done 
    count2=-1 
done 
exit 0 

Это должно работать.

1

Для петли лучше, чем цикл while. Ваша реализация может быть упрощена:

#! /bin/bash 
network_id="192.168." 
for i in {0..255}; do 
    for j in {0..255}; do 
     printf "%s%s%s%s\n" $network_id $i "." $j 
    done 
done 
exit 0 

Edit: Спасибо за предложение Ghoti в. Помните, что вам может потребоваться настроить линию shebang в соответствии с вашими потребностями. Больше обсуждений можно найти в: What is difference between #!/bin/sh and #!/bin/bash? и Why is it better to use “#!/usr/bin/env NAME” instead of ....

+1

На мой комментарий к вопросу, я рекомендую не использовать '{0..255}', если вы указали shebang из '#!/Bin/sh'. Наиболее очевидно, что не все '/ bin/sh'es являются bash. (У меня есть поле Ubuntu, в котором ['/ bin/sh' is * dash *] (https://wiki.ubuntu.com/DashAsBinSh) вместо bash.) Если вы собираетесь выполнять переносимость и соответствие POSIX, использовать базисы. – ghoti

+0

@ghoti: Хорошая точка. Я исправил это. – Quinn

+1

Замена shebang является менее идеальным решением. Замена конструкций контуров чем-то портативным POSIX, возможно, станет лучшим решением. – tripleee

1

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

#! /bin/sh 
network_id="192.168." 
count1=-1 
while [ "$count1" -le 254 ] 
do 
    count1=$(($count1+1)) 
    count2=-1 
    while [ "$count2" -le 254 ] 
    do 
     count2=$(($count2+1)) 
     printf "%s%s%s%s\n" $network_id $count1 "." $count2 
    done 
done 
exit 0 
2

Ну, @uint128_t поймал ошибку.

Ваш скрипт пытается попытаться распечатать все IP-адреса в пределах 192.168.0.0/16, а не всех сетей класса C с этим префиксом, поэтому я буду считать, что ваш код является лучшим описанием результата, который вы «Ищем.

И я представить следующее в качестве «лучшего использования Баш»:

#!/usr/bin/env bash 

# Declare an array 
ip=(192 168 -1 -1) 

# Step through the third quad in the array 
while [ $((ip[2]++)) -lt 255 ]; do 
    # Step through the fourth quad in the array 
    while [ $((ip[3]++)) -lt 255 ]; do 
     # Print the array, with dots as a field separator 
     IFS=. eval echo '"${ip[*]}"' 
    done 
    # Reset the last quad once we're done with this subnet 
    ip[3]=-1 
done 

Там будут те, кто говорит, что eval это зло, но это совершенно безопасно в этом контексте, где входные данные и вы защищаете вещи одинарными кавычками.

Это решение позволяет избежать дополнительных счетчиков и, возможно, дает вам возможность делать другие вещи с помощью ваших IP-адресов, если вы этого хотите.

Следует упомянуть еще одну тонкость, которая составляет [ $((ip[2]++)) -lt 255 ]. Это увеличивает элемент массива, но потому, что ++ ПОСЛЕ переменной, значение, которое используется для сравнения (-le), является значением, которое предшествует приращению. Таким образом, мы останавливаем цикл, когда сравниваемое число меньше 255, потому что это означает, что последний прогон цикла произойдет, когда переменная увеличится на один выше, до 255.Если по какой-то причине вы хотели бы сравнить значение после инкремента, а не раньше, вы можете добавить переменную ++ вместо ее добавления: $((++ip[2])).


Другой забавный подход может извлечь выгоду из того, что IP-адреса просто числа, и что пунктирные квадроциклы являются переводом этого номера:

#!/usr/bin/env bash 

# Set your start and maximum IPs as integers 
ip=$((192*2**24 + 168*2**16)) 
max=$((ip + 255*2**8 + 255)) 

# Convert each integer into dotted quad notation 
while [ $ip -le $max ]; do 
    echo $((ip/2**24)).$((ip/2**16 %256)).$((ip/2**8 % 256)).$((ip % 256)) 
    ((ip++)) 
done 
1

Вы можете использовать 1 цикл:

i=0 
((max=256 * 256)) 
while [ $i -lt ${max} ]; do 
     ((major=i/256)) 
     ((minor=i%256)) 
     printf "%s.%s.%s.%s\n" "192" "168" ${major} ${minor} 
     ((++i)) 
done 
Смежные вопросы