В вашем сценарии используются три функции оболочки Bash, которые предоставляются не всеми оболочками в стиле Борна. Как говорит Химэйл , вы можете просто запустить этот скрипт bashвместо sh. Ваша строка hashbang вверху ( #!/bin/bash) указывает, bashно эффективна только если вы выполняете скрипт, как объяснил heemayl . Если вы передадите имя скрипта sh, shон не будет автоматически вызываться bash, а просто запустит скрипт. Это потому, что когда ваш скрипт действительно запущен, строка hashbang не имеет никакого эффекта .
Другой вариант, если вам нужно написать полностью переносимые скрипты, которые не зависят от функций Bash, - это изменить ваш скрипт так, чтобы он работал без них. Используемые вами функции Bash:
- Массив . Это было первым, так что именно это и привело к ошибке, когда вы пытались запустить скрипт с помощью оболочки Dash . Выражение в скобках
( {a..z} ), которое вы назначаете chars, создает массив и ${chars[i]}, который появляется в вашем цикле, индексирует его.
- Брекет-расширение. В Баше, а также во многих других оболочках,
{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-стиле альтернативный
for-loop синтаксис . Несмотря на то, что он основан на арифметическом расширении , которое не является специфическим для Bash (хотя некоторые очень старые, не POSIX-совместимые оболочки также не имеют его), forцикл в стиле C представляет собой Bash-ism и не является широко переносимым для другие снаряды.
Bash широко доступен, особенно в системах GNU / Linux, таких как Ubuntu, и (как вы видели) также доступен в macOS и многих других системах. Учитывая, сколько вы используете специфичных для Bash функций, вы можете просто захотеть использовать их и просто убедиться, что вы используете Bash (или какую-либо другую оболочку, которая поддерживает используемые вами функции) при запуске ваших сценариев.
Однако вы можете заменить их переносимыми конструкциями, если хотите. Массив и forцикл в стиле C легко заменить; генерация диапазона букв без расширения фигурных скобок (и без жесткого кодирования их в вашем скрипте) - это немного сложная часть.
Во-первых, вот скрипт, который печатает все строчные латинские буквы:
#!/bin/sh
for i in $(seq 97 122); do
printf "\\$(printf %o $i)\n"
done
- Команда
seqгенерирует числовые последовательности. $( )выполняет подстановку команды , поэтому $(seq 97 122)заменяется выводом seq 97 122. Это коды символов для aсквозного z.
- Мощная
printfкоманда может превратить коды символов в буквы (например, printf '\141'печатные издания a, за которыми следует новая строка ), но коды должны быть в восьмеричном виде , а выводиться seqтолько в десятичном виде . Итак, я использовал printfдважды: внутренний printf %o $iпреобразует десятичные числа (предоставленные seq) в восьмеричные, и подставляется во внешнюю printfкоманду. (Хотя также возможно использование шестнадцатеричного числа , оно не проще и кажется менее переносимым .)
printfинтерпретирует \сопровождаемое восьмеричным числом как символ с этим кодом и \nкак новую строку. Но оболочка также использует \в качестве escape-символа. \Перед $помешают $от вызывая расширение произойдет (в данном случае, команда подстановки ), но я не хочу , чтобы предотвратить это, так что я избежал его с другим \; вот причина \\. Второй , \прежде чем nне нужно экранировать , так как , в отличие от \$, \nне имеет особого значения для оболочки в двойных кавычках.
- Для получения дополнительной информации о том, как двойные кавычки и обратный слеш используются в программировании оболочки, см. Раздел о цитировании в международном стандарте . См. Также 3.1.2 Цитирование в Справочном руководстве Bash , особенно 3.1.2.1 Escape-символ и 3.1.2.3 Двойные кавычки . (Вот весь раздел в контексте.) Обратите внимание, что одинарные кавычки (
') также являются важной частью синтаксиса цитирования оболочки, я просто не использовал их в этом сценарии.
Это переносимо для большинства Unix-подобных систем и не зависит от того, какую оболочку в стиле Bourne вы используете. Тем не менее, некоторые Unix-подобные системы не seqустановлены по умолчанию ( jotвместо этого они, как правило, используют , что не устанавливается по умолчанию в большинстве систем GNU / Linux). Вы можете использовать цикл с exprили арифметической заменой для дальнейшего увеличения переносимости, если вам необходимо:
#!/bin/sh
i=97
while [ $i -le 122 ]; do
printf "\\$(printf %o $i)\n"
i=$((i + 1))
done
Это использует while-loop с в [команде , чтобы продолжить цикл только тогда , когда $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 ]).