У меня есть каталог с именем DS1
. Я пытаюсь скопировать его 4 раза, поэтому у меня также есть DS2
, DS3
, DS4
и DS5
.
Я могу использовать следующую команду с терминала, и она работает:
for i in {2..5}; do cp -r /home/test/DS1 "DS$i"; done
Однако, когда я ввожу ее в такой сценарий:
#!/bin/sh
for i in {2..5}; do cp -r /home/test/DS1 "DS$i"; done
Создается один каталог с именем DS {2..5 }
вместо каталогов с шагом от 2 до 5. Не понимаю, что делаю не так.
{2..5}
— это расширение фигурной скобки. Расширение скобок не стандартизировано POSIX.Некоторые, но не все, широко используемые оболочки в стиле Борна поддерживают его.
Оболочкой, с которой вы взаимодействуете в терминале Ubuntu, является bash
, если вы намеренно не используете другую. bash
поддерживает раскрытие фигурных скобок. Но shebang в вашем скрипте для sh
, который в Ubuntu является символической ссылкой на тире
. дефис
не поддерживает раскрытие фигурных скобок.
Таким образом, вы можете либо:
bash
(или сценарием для какой-либо другой оболочки, поддерживающей раскрытие фигурных скобок, например zsh
или ksh
). тире
. Если вы хотите сделать свой скрипт скриптом bash
, замените
#!/bin/sh
на:
#!/bin/bash
Тогда при запуске как ./scriptname
он будет запущен в баш
. Если вы запускаете свой скрипт, написав sh имя_сценария
, тогда вы должны вместо этого использовать bash имя_сценария
.
Если вы хотите исключить раскрытие фигурных скобок, есть несколько альтернатив. Я предлагаю seq
с заменой команд, которая, вероятно, является наиболее распространенной альтернативой раскрытию фигурных скобок, проста в написании и, вероятно, понятна другим читателям.
Вместо {2..5}
вы можете написать $(seq 2 5)
.Поскольку оно не заключено в кавычки, то есть поскольку оно равно $(
)
, а не "$(
)"
-- разбиение поля (который в bash
называется разбиением слов) выполняется над результатом. Пока вы не установили для переменной оболочки IFS
, которая управляет разделением полей, значение, содержащее любую цифру или не содержащее новой строки, это будет делать то, что вы хотите.
(Подстановка – также называемая расширением имени файла, также называемая расширением пути – также выполняется в результате подстановки команды без кавычек, но вывод of seq
не будет содержать подстановочных символов ?
, *
или [
, так что в данном случае это не действует .)
Обратите внимание, что seq
не стандартизовано POSIX. Это будет работать практически на любой системе GNU/Linux и некоторых других Unix-подобных операционных системах, но некоторые Unix-подобные ОС не имеют установленного по умолчанию seq
(обычно они имеют jot
. ]), поэтому не гарантируется, что он будет работать во всех Unix-подобных операционных системах.
Когда вы запускаете скрипт в своем терминале, скорее всего, вы используете оболочку Bash. Bash поддерживает раскрытие скобок , поэтому {2..5}
расширяется до последовательности 2 3 4 5
, и ваш скрипт работает так, как вы ожидаете.
Однако когда вы добавляете тот же скрипт в файл, он не работает. Это происходит из-за shebang, который вы используете (#!/bin/sh
), который сообщает вашему сценарию, что он должен выполняться в оболочке sh, которая совместима с POSIX и не поддержка расширения брекетов.
Так что у вас есть два варианта:
#!/bin/bash
или другую оболочку, которая поддерживает раскрытие фигурных скобок. или
#!/bin/sh
и замените {2..5}
на $(seq 2 5)
. Также взгляните на этот интересный вопрос Stack Overflow о различиях между sh и Bash.