Создание сценария для каталога cp несколько раз

У меня есть каталог с именем 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. Не понимаю, что делаю не так.

0
задан 11 August 2020 в 21:37

2 ответа

{2..5} — это расширение фигурной скобки. Расширение скобок не стандартизировано POSIX.Некоторые, но не все, широко используемые оболочки в стиле Борна поддерживают его.

Оболочкой, с которой вы взаимодействуете в терминале Ubuntu, является bash, если вы намеренно не используете другую. bash поддерживает раскрытие фигурных скобок. Но shebang в вашем скрипте для sh, который в Ubuntu является символической ссылкой на тире. дефис не поддерживает раскрытие фигурных скобок.

Таким образом, вы можете либо:

  1. Сделать свой сценарий сценарием bash (или сценарием для какой-либо другой оболочки, поддерживающей раскрытие фигурных скобок, например zsh или ksh ).
  2. Замените раскрытие фигурных скобок в вашем скрипте на то, что работает в тире.

Если вы хотите сделать свой скрипт скриптом 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-подобных операционных системах.

8
ответ дан 11 August 2020 в 19:07

Когда вы запускаете скрипт в своем терминале, скорее всего, вы используете оболочку Bash. Bash поддерживает раскрытие скобок , поэтому {2..5} расширяется до последовательности 2 3 4 5, и ваш скрипт работает так, как вы ожидаете.

Однако когда вы добавляете тот же скрипт в файл, он не работает. Это происходит из-за shebang, который вы используете (#!/bin/sh), который сообщает вашему сценарию, что он должен выполняться в оболочке sh, которая совместима с POSIX и не поддержка расширения брекетов.

Так что у вас есть два варианта:

  1. Изменить шебанг на #!/bin/bash или другую оболочку, которая поддерживает раскрытие фигурных скобок.

или

  1. Используйте #!/bin/sh и замените {2..5} на $(seq 2 5).

Также взгляните на этот интересный вопрос Stack Overflow о различиях между sh и Bash.

5
ответ дан 11 August 2020 в 19:06

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

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