cp с пробелами и специальными символами отлично работает на терминале, но не в скрипте

Вместо того, чтобы пытаться решить заданный вами вопрос, этот ответ предлагает решение, которое пытается решить основную проблему. Для этого примера я предположил, что аргументы aи sявляются логическими значениями (переключателями ), но аргумент lпринимает параметр:

unset -v flagA flagS valueL
while getopts "al:s" OPT
do
    case "$OPT" in
        a)    echo "Got a"; flagA=true ;;
        s)    echo "Got s"; flagS=true ;;
        l)    printf 'Got l with value "%s"\n' "$OPTARG"; valueL="$OPTARG" ;;
    esac
done
shift "$((OPTIND - 1))"

printf '%s\n' "flagA=${flagA-unset}, flagS=${flagS-unset}, valueL=${valueL-unset}"
if [ "$#" -gt 0 ]; then
  printf 'Other arguments:\n'
  printf ' - "%s"\n' "$@"
fi

Дополнительная информация на справочной странице bash.

1
15.04.2020, 18:10
1 ответ

Кажется, вы хотите скопировать определенный файл из ~/Downloadsв ~/Documents/books.

Прежде всего следует отметить, что ~не ведет себя как переменная. В частности, он не расширяется до пути к вашему домашнему каталогу, когда он заключен в кавычки. Поэтому в сценариях лучше использовать $HOMEдля ссылки на домашний каталог.

Во-вторых, вы, кажется, добавляете буквальные одинарные кавычки к значению вашей переменной $a. В этом нет необходимости, и это приведет только к ошибке «Нет такого файла или каталога» (, поскольку в имени файла нет одинарных кавычек ).

В-третьих, вы должны стараться избегать использования lsв сценариях. В этом случае, например, если $1— это просто имя файла в ~/Downloads, вам вообще не нужно его искать. Кроме того, использование grep $1проблематично по целому ряду причин:

  • grepв основном используется в текстовых документах . Теоретически имена файлов могут содержать символы новой строки, из-за чего «выборка» имен файлов работает только в том случае, если известно, что имена или «хорошие».
  • $1не заключен в кавычки, поэтому grepможет сбить с толку, если он содержит пробелы или другие специальные символы. Если $1равно *, оно будет расширяться, например, до всех имен файлов в текущем каталоге.
  • Если строка $1начинается с дефиса, она будет принята как опция к grep.

Итак,ваш скрипт может быть записан как

#!/bin/sh

name="$HOME/Downloads/$1"

printf 'The filename is "%s"\n' "$name"

cp "$name" "$HOME/Documents/books"

Команда printfпредназначена для вывода имени файла, который мы выбрали. Я вывожу двойные кавычки вокруг имени, но в имени нет двойных кавычек. Вместо этого я обязательно цитирую $nameв вызове cpв последней строке. Фактически, я удостоверяюсь, что цитирую все расширения , которые, как я знаю, в противном случае привели бы к разделению значения переменной оболочкой.

Вы можете использовать этот скрипт как

./script.sh 'Ian Goodfellow, Yoshua Bengio, Aaron Courville - Deep Learning [pre-pub version] (2016, MIT Press).pdf'

Имя файла должно быть заключено в кавычки, так как оно содержит пробелы и символы, которые в противном случае являются особыми в оболочке.

Если вы хотите, чтобы ваш скрипт искал файл, содержащий слово, указанное в командной строке, чтобы вы могли произнести

./script.sh Goodfellow

Затем используйте данную строку в шаблоне подстановки:

#!/bin/sh

for name in "$HOME/Downloads"/*"$1"*.pdf; do
    printf 'Will copy the file "%s"\n' "$name"
    cp "$name" "$HOME/Documents/books"
done

Теперь сценарий примет первый аргумент и переберет все .pdfфайлы в ~/Downloads, которые содержат заданную строку в имени файла. Каждый такой файл будет скопирован в ~/Documents/books.

Если вы используете Unix, где cp -vбудет подробно копировать файлы, сценарий может быть еще больше уменьшен:

#!/bin/sh

cp -v "$HOME/Downloads"/*"$1"*.pdf "$HOME/Documents/books"

Это предотвращает форматирование вывода самостоятельно («Будет копировать…» ), так как мы больше не перебираем имена файлов, соответствующие заданному шаблону. Вместо этого мы просто полагаемся на тот факт, что если вы дадите несколько имен файловcp(и шаблон подстановки вполне может расшириться до нескольких имен файлов ), то их можно будет скопировать с помощью одной команды в какой-либо каталог назначения.


См. также:

2
19.03.2021, 02:28

Теги

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