
При запуске следующего скрипта возникает следующая ошибка:
cp: cannot stat ls
Содержание сценария
#!/bin/bash
#make copies of all files in directory
cd /home/don
LIST='ls'
for i in $LIST; do
ORIG=$i
DEST=$i.old
cp $ORIG $DEST
echo "Copied $i"
done
Кто-нибудь видит проблему?
решение1
Одна из главных ошибок заключается в том, что вы пытаетесь использовать команду ls
, но переменная LIST содержит только строку 'ls'. Вы можете использовать подстановку команд с синтаксисом $(command)
. Я бы не советовал этого делать в этом случае, так как это не даст вам информацию в формате, который вы можете легко использовать. Это почти всегдаошибка при анализе выводаls
.
В этом случае вам следует использовать сопоставление с образцом оболочки, также известное какподстановка.
Вместо этого я бы предложил следующий метод в вашем сценарии:
#!/bin/bash
#make copies of all files in directory
for i in /home/don/* ; do
if [[ -f $i ]]; then
orig="$i"
dest="${i}.old"
cp "$orig" "$dest"
echo "Copied $i"
else
echo "${i} is not a file"
fi
done
- При этом используется подстановка символов оболочки для сопоставления всех файлов в каталоге.
./*
означает все в текущем каталоге (.
). - Оператор
if
проверяет, является ли совпадение файлом (для каталогов и ссылок проверка невозможна), и, если это так, выполняет последовательность копирования. - Я изменил имена переменных на строчные, поскольку системные переменные среды пишутся заглавными буквами, чтобы избежать нежелательных конфликтов имен.
решение2
Ну, в вашем скрипте есть небольшая ошибка. В четвертой строке вы имели в виду выполнитьлспоэтому его не следует заключать в одинарные кавычки, а следует обернуть внутри символа``. Итак, ваш скрипт меняется следующим образом
LIST=`ls`
Попробуйте обновить скрипт, как указано выше.
Однако желательно не использовать его $(ls)
вообще, а отдать предпочтение подстановке оболочки в заголовке цикла.
for i in *; do
ПодобноГ-н Дэвид Андерссонпрокомментировал ниже, что это можно использовать с кавычками для значений переменных ("$i") для следующих за ним операторов, иначе могут возникнуть проблемы с пробелами в именах файлов. Вы можете предотвратить это, используя find в сочетании с заменой процесса:
while read l; do
i=$(basename "$l")
done < <(find . -name '*' -maxdepth 1)
Подробный ответ со сценарием и пояснениями дан ниже.Г-н Арроникал. Пожалуйста, ссылайтесь на него для улучшения сценариев в будущем.
решение3
Версия команды «find»
Ваш скрипт может быть реализован как однострочная find
команда, без необходимости разбора ls
или возни с подстановками и т. д.
Ваша цель, насколько гласит вопрос, сделать копии всех файлов в текущем каталоге. Для этого соответствующая команда будет:
find . -maxdepth 1 -mindepth 1 -exec cp {} {}".old" \;
Что это делает, так это то, что find
работает со всеми файлами в .
(текущем) каталоге и вызывает cp
для каждого файла (следовательно \;
). Поскольку find
это рекурсивно, это мы должны ограничить глубину поиска, следовательно, -maxdepth
флаг, а -mindepth
флаг — это избежать перечисления .
в качестве одного из результатов поиска.
Пример запуска:
$ touch "file one" "file two"
$ find . -maxdepth 1 -mindepth 1 -exec cp {} {}".old" \;
$ ls -1
file one
file one.old
file two
file two.old
$
ПРИМЕЧАНИЕ: cp
все равно будет жаловаться на каталоги. Есть несколько способов справиться с этим.
1) вы можете отфильтровать только файлы, если это ваша цель, с помощью -type f
флага в find
like
find . -mindepth 1 -maxdepth 1 -type f -exec cp {} {}".old" \;
2) Используйте cp -r
также для создания копий каталогов
find . -mindepth 1 -maxdepth 1 -exec cp -r {} {}".old" \;
Однострочник на Python
Этот вариант немного длиннее find
предыдущего, но все равно выполняет свою работу и не имеет проблем со специальными именами файлов.
python -c 'import shutil; import os;[shutil.copyfile(f,f + ".old") for f in os.listdir(".") if os.path.isfile("./" + f)]'
Пример запуска:
$ touch "test file 1" "testfile 2"
$ python -c 'import shutil;import os;[shutil.copyfile(f,f + ".old")
> for f in os.listdir(".")
> if os.path.isfile("./" + f)]'
$ ls -1
test file 1
test file 1.old
testfile 2
testfile 2.old
$
Чтобы включить каталоги, используйтеshutil.copytree(source,destination)
python -c 'import shutil; import os;[shutil.copyfile(f,f + ".old") if os.path.isfile("./" + f) else shutil.copytree(f,f + ".old") for f in os.listdir(".")]'
Обратите внимание, что это не удастся, если, скажем, directory_one.old/
уже существует