Для цикла с Алфавитом

Это работает отлично над OSX

#!/bin/bash
chars=( {a..z} )
n=3
for ((i=0; i<n; i++))
do
  echo "${chars[i]}"
done

Но когда я выполняю его на Ubuntu, я получаю следующую ошибку.

ForLoopAlphabetTest.sh: 2: ForLoopAlphabetTest.sh: Syntax error: "(" unexpected

Я, может казаться, не решаю проблему. Какие-либо предложения?

12
задан 18 January 2017 в 19:57

2 ответа

По-видимому, Вы запускаете скрипт как:

sh ForLoopAlphabetTest.sh

В Ubuntu, sh symlinked к dash; как dash не имеет никакого понятия массивов, Вы получаете синтаксическую ошибку для (.

Сценарий работает отлично над bash, таким образом, было бы хорошо при выполнении его как bashаргумент:

bash ForLoopAlphabetTest.sh

Теперь, Вы имеете bash хижина на сценарии, таким образом, Вы могли сделать исполняемый файл сценария (chmod u+x ForLoopAlphabetTest.sh), и выполненный это как:

/path/to/ForLoopAlphabetTest.sh

или из каталога сценария:

./ForLoopAlphabetTest.sh

Также обратите внимание, что, Ваш сценарий содержит расширение фигурной скобки {a..z}, и C-стиль for конструкция: for (( ... )) которые также не поддерживаются dash; таким образом, если Вашей целью является мобильность, необходимо посмотреть на POSIX sh синтаксисы только.

25
ответ дан 23 November 2019 в 03:29

Ваш сценарий использует три функции оболочки Bash, которые не обеспечиваются всеми оболочками стиля Границы. Как heemayl говорит, можно просто запустить тот скрипт с bash вместо sh. Ваша hashbang строка наверху (#!/bin/bash) указывает bash но является только эффективным, если Вы выполняете сценарий, как heemayl объясненный. Если Вы передаете название сценария к sh, sh не будет автоматически звонить bash, но просто запустит скрипт. Это вызвано тем, что, после того как Ваш сценарий на самом деле работает, hashbang строка не имеет никакого эффекта.

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

Bash широко доступен, особенно в системах GNU/Linux как Ubuntu, и (как Вы видели), также доступно на macOS и многих других системах. Рассмотрение, насколько Вы используете определенные для Bash функции, Вы могли бы просто хотеть использовать их и просто удостовериться, что Вы используете Bash (или некоторая другая оболочка, которая поддерживает функции, которые Вы используете), когда Вы запускаете свои скрипты.

Однако можно заменить их портативными конструкциями, если Вам нравится. Массив и C-стиль for цикл легко заменить; генерация диапазона букв без расширения фигурной скобки (и без жесткого кодирования их в Вашем сценарии) является одной частью, это немного хитро.


Во-первых, вот сценарий, который печатает все строчные латинские буквы:

#!/bin/sh

for i in $(seq 97 122); do
    printf "\\$(printf %o $i)\n"
done

Это портативно к большинству подобных Unix систем и не зависит, какую оболочку стиля Границы Вы используете. Однако несколько подобных Unix систем не имеют seq установленный по умолчанию (они склонны использовать jot вместо этого, который не установлен по умолчанию большинство систем GNU/Linux). Можно использовать цикл с expr или арифметическая замена для увеличения мобильности далее, если Вы должны:

#!/bin/sh

i=97
while [ $i -le 122 ]; do
    printf "\\$(printf %o $i)\n"
    i=$((i + 1))
done

Это использует a while- цикл с [ команда для продолжения цикличного выполнения только, когда $i находится в диапазоне.


Вместо того, чтобы печатать целый алфавит, Ваш сценарий определяет переменную n и печатает первое $n строчные буквы. Вот версия Вашего сценария, который не полагается ни на какие определенные для Bash функции и работы над Тире, но требует seq:

#!/bin/sh

n=3 start=97
for i in $(seq $start $((start + n - 1))); do
    printf "\\$(printf %o $i)\n"
done

Корректировка значения n изменения, сколько букв печатается, как в Вашем сценарии.

Вот версия, которая не требует seq:

#!/bin/sh

n=3 i=97 stop=$((i + n))
while [ $i -lt $stop ]; do
    printf "\\$(printf %o $i)\n"
    i=$((i + 1))
done

Там, $stop один выше, чем код символа последней буквы, которая должна быть распечатана, таким образом, я использую -lt (меньше, чем), а не -le (меньше чем или равный) с [ команда. (Это также работало бы для создания stop=$((i + n - 1)) и используйте [ $i -le $stop ]).

10
ответ дан 23 November 2019 в 03:29

Другие вопросы по тегам:

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