Запутанная синтаксическая ошибка рядом с неожиданной знак 'Сделано'

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

#!/bin/bash
names=(test test2 test3 test4)
for name in ${names[@]}
do
        #do something
done

однако, когда я запускаю этот скрипт я получаю следующие ошибки:

./test.sh: строка 6: синтаксическая ошибка рядом с неожиданным токеном"
. /test.sh: строка 6: готово'

что я пропустил здесь? вкладка shell-скрипты "чувствительные"?

6 ответов


нет, сценарии оболочки не чувствительны к вкладке (если вы не делаете что-то действительно сумасшедшее, чего вы не делаете в этом примере).

вы не можете иметь пустой while do done блок, (комментарии не в счет) Попробуйте заменить echo $name вместо

#!/bin/bash
names=(test test2 test3 test4)
for name in ${names[@]}
do
       printf "%s " $name
done
printf "\n"

выход

test test2 test3 test4

dash и bash немного мозг мертв в этом случае, они не позволяют пустой цикл, поэтому вам нужно добавить команду no op, чтобы сделать этот запуск, например true или :. Мои тесты предполагают : немного быстрее, хотя они должны быть одинаковыми не знаю, почему:

time (i=100000; while ((i--)); do :; done)

средняя N принимает 0.262 секунд, в то время как:

time (i=100000; while ((i--)); do true; done)

принимает 0.293 секунд. Интересно:

time (i=100000; while ((i--)); do builtin true; done)

принимает 0.356 считанные секунды.

все измерения в среднем 30 пробегов.


Bash имеет встроенный no-op, двоеточие (:), которое является более легким чем нерест другого процесса для запуска true.

#!/bin/bash
names=(test test2 test3 test4)
for name in "${names[@]}"
do
    :
done

EDIT: Уильям правильно указывает, что true также является встроенной оболочкой, поэтому возьмите этот ответ как еще один вариант FYI, а не лучшее решение, чем использование true.


вы можете заменить ничего на "true" вместо этого.


вам нужно что-то в вашем цикле, иначе Баш жалуется.


эта ошибка ожидается с некоторыми версиями bash, где скрипт был отредактирован в Windows, и поэтому скрипт на самом деле выглядит следующим образом:

#!/bin/bash^M
names=(test test2 test3 test4)^M
for name in ${names[@]}^M
do^M
       printf "%s " $name^M
done^M
printf "\n"^M

где ^M представляет символ возврата каретки (0x0D). Это можно легко увидеть в vi, используя двоичный параметр, как в:

vi -b script.sh

чтобы удалить эти символы возврата каретки, просто используйте команду vi:

1,$s/^M//

(обратите внимание, что ^M выше является одним символом возврата каретки, чтобы ввести его в редактор использует sequence Control - V Control-M)