Вместо того, чтобы пытаться решить заданный вами вопрос, этот ответ предлагает решение, которое пытается решить основную проблему. Для этого примера я предположил, что аргументы 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
.
Кажется, вы хотите скопировать определенный файл из ~/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
(и шаблон подстановки вполне может расшириться до нескольких имен файлов ), то их можно будет скопировать с помощью одной команды в какой-либо каталог назначения.
См. также: