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

Это отлично работает на 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

Я не могу решить проблему вопрос. Любые предложения?

1
задан 19 January 2017 в 06:57

1 ответ

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

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

Массив. Это на первом месте, поэтому это вызвало ошибку при попытке запустить ваш скрипт с помощью оболочки Dash. Выражение в скобках ( {a..z} ), которое вы назначаете chars, создает массив, а ${chars[i]}, который появляется в вашем цикле, индексирует его. Расширение скобы. В Bash, а также во многих других оболочках {a..z} расширяется до a b c d e f g h i j k l m n o p q r s t u v w x y z. Однако это не универсальная (или стандартизованная) функция оболочек в стиле Бурна, а Dash не поддерживает ее. Синтаксис синтаксиса C-style alternate for -loop. Хотя на основе арифметического расширения, которое не является специфичным для Bash (хотя некоторые очень старые, не совместимые с POSIX оболочки не имеют его), цикл C [style] for является Bash-ism и не является широко переносимый другими оболочками.

Bash широко доступен, особенно в системах GNU / Linux, таких как Ubuntu, и (как вы видели) также доступен для MacOS и многих других систем. Учитывая, насколько вы используете специфичные для Bash функции, вы можете просто использовать их и просто убедитесь, что используете Bash (или другую оболочку, поддерживающую используемые функции) при запуске ваших скриптов. [ ! d20]

Однако вы можете заменить их переносимыми конструкциями, если хотите. Массив и цикл C [style] for легко заменить; (d22)

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

#!/bin/sh

for i in $(seq 97 122); do
    printf "\\$(printf %o $i)\n"
done
Массив. Это на первом месте, поэтому это вызвало ошибку при попытке запустить ваш скрипт с помощью оболочки Dash. Скопированное выражение ( {a..z} ), которое вы назначаете chars, создает массив, а ${chars[i]}, который появляется в вашем цикле, индексирует его. array может поменять коды символов в буквы (например, printf '\141' печатает a, а затем новая строка), но коды должны быть с оболочкой Dash , а seq выводится только в десятичном формате. Поэтому я дважды использовал printf: внутренняя printf %o $i преобразует десятичные числа (предоставленные seq) в восьмеричную и заменяется на внешнюю команду printf. (Хотя также можно использовать шестнадцатеричный, это не проще и кажется менее переносимым.) Расширение скобки. В Bash, а также во многих других оболочках {a..z} расширяется до a b c d e f g h i j k l m n o p q r s t u v w x y z. Тем не менее, это не универсальная (или стандартизованная) функция оболочек в стиле Бурна, а Dash не поддерживает ее. Для получения дополнительной информации о том, как двойные кавычки и обратная косая черта используются в программировании оболочки, см. Расширение скобы. . См. Также 3.1.2. Цитирование в Справочном руководстве Bash, особенно 3.1.2.1 Escape Character и 3.1.2.3 Double Quotes. (Вот весь раздел в контексте.) Обратите внимание, что одиночные кавычки (') также являются важной частью синтаксиса цитирования оболочки, я просто не использовал их в этом скрипте.

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

#!/bin/sh

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

Использует while -loop с [ f50] продолжить цикл только тогда, когда $i находится в диапазоне.

Вместо того, чтобы печатать весь алфавит, ваш скрипт определяет переменную n и печатает первые $n строчные буквы. Вот версия вашего скрипта, которая не использует никаких специфичных для Bash функций и работает с Dash, но требует 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 ]).

8
ответ дан 23 May 2018 в 02:19
  • 1
    Это феноменально подробный ответ, чем вы за образование. Я очень начинающий, поэтому мой способ написания сценариев - довести рабочие элементы, найденные в Интернете, до тех пор, пока это не сработает. Я не сомневаюсь, что есть 1) лучше и 2) более простые способы делать то, что я создаю со сценариями, и вышеизложенное дает долгий путь в этом. – denski 19 January 2017 в 13:17

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

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