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

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

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

a=$(ls ~/Downloads/ | grep $1)
a="'$a'"
a="~/Downloads/"$a
echo $a
cp $a ~/Documents/books/.

Когда я цитирую имя файла, это нормально работает на терминале. Но в скрипте слова обрабатываются как отдельные аргументы. В приведенном выше скрипте, когда $a выводится, выдается что-то вроде:

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

Вы видите, что имя файла заключено в кавычки. Когда указанный выше аргумент передается в cp на терминале, он работает нормально, но не в скрипте. Пожалуйста, помогите.

решение1

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

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

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

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

  • grepв основном используется в текстедокументы. Имена файлов теоретически могут содержать новые строки, что делает «grepping» имен файлов работоспособным только в том случае, если известно, что имена «хорошие».
  • $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"

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


Смотрите также:

Связанный контент