В вашем скрипте есть различные возможные точки отказа. Прежде всего, rm *.old*
будем использовать глобирование для создания списка всех подходящих файлов, которые могут иметь дело с именами файлов, содержащими пробелы. Однако ваш сценарий назначает переменную каждому результату глобуса и делает это без кавычек. Это сломается, если ваши имена файлов содержат пробелы. Например:
$ ls
'file name with spaces.old.txt' file.old.txt
$ rm *.old.* ## works: both files are deleted
$ touch "file.old.txt" "file name with spaces.old.txt"
$ for i in ./*; do oldfile=$i; rm -v $oldfile; done
rm: cannot remove './file': No such file or directory
rm: cannot remove 'name': No such file or directory
rm: cannot remove 'with': No such file or directory
rm: cannot remove 'spaces.old.txt': No such file or directory
removed './file.old.txt'
Как видите, цикл не удался для файла с пробелами в его имени. Чтобы сделать это правильно, вам нужно заключить переменную в кавычки:
$ for i in ./*; do oldfile="$i"; rm -v "$oldfile"; done
removed './file name with spaces.old.txt'
removed './file.old.txt'
Та же проблема касается почти каждого использования $i
в вашем скрипте. Вы должны всегда указывать свои переменные .
Следующая возможная проблема заключается в том, что вы, похоже, ожидаете, что *.old.*
файлы совпадут с расширением .old
. Это не так. Он соответствует «0 или более символов» ( *
), затем a .
, затем «old», затем другому, .
а затем «0 или более символов снова». Это означает, что он не будет совпадать с чем-то вроде file.old
, а только с чем-то вроде `file.old.foo:
$ ls
file.old file.old.foo
$ for i in *; do if [[ "$i" == *.old.* ]]; then echo $i; fi; done
file.old.foo
Таким образом, противник не совпадает file.old
. В любом случае ваш сценарий намного сложнее, чем нужно. Попробуйте это вместо этого:
#!/bin/bash
for i in *; do
if [[ -f "$i" ]]; then
if [[ "$i" == *.old ]]; then
rm -v "$i" || echo "rm failed for $i"
else
echo "$i doesn't have an .old extension"
fi
cp -v "$i" "$i".old
else
echo "$i is not a file"
fi
done
Обратите внимание, что я добавил -v
к операторам rm
и cp which does the same thing as what you were doing with your
echo`.
Это не идеально, поскольку, когда вы найдете, например, file.old
что это будет удалено, а позже скрипт попытается скопировать его и потерпит неудачу, так как файл больше не существует. Тем не менее, вы не объяснили, что на самом деле пытается сделать ваш сценарий, поэтому я не могу исправить это для вас, если вы не скажете нам, что вы действительно пытаетесь выполнить.
Если вы хотите: i) удалить все файлы с .old
расширением и ii) добавить .old
расширение к любым существующим файлам, у которых его нет, все, что вам действительно нужно, это:
#!/bin/bash
for i in *.old; do
if [[ -f "$i" ]]; then
rm -v "$i" || echo "rm failed for $i"
else
echo "$i is not a file"
fi
done
## All the ,old files have been removed at this point
## copy the rest
for i in *; do
if [[ -f "$i" ]]; then
## the -v makes cp report copied files
cp -v "$i" "$i".old
fi
done
rm *.old.*
удаляются эти файлы. но не файл резервной копии file.old. Я пытаюсь сделать это в моем сценарии. СпасибоЕдинственные случаи
rm $oldfile
могли не то, когда ваше имя файла содержит любой символIFS
(пробел, табуляция, перевод строки) или любой Глоб символ (*
,?
,[]
).Если присутствует какой-либо символ,
IFS
оболочка выполнит разбиение по словам и на основе присутствия глобальных символов расширения имени пути в расширении переменной.Так, например, если имя файла
foo bar.old.
, переменнаяoldfile
будет содержатьfoo bar.old.
.Когда вы делаете:
shell сначала разбивает расширение
oldfile
на пространство на два слова,foo
иbar.old.
. Таким образом, команда становится:что, очевидно, приведет к неожиданному результату. Кстати, если у вас есть какие - либо подстановка операторов (
*
,?
,[]
) в разложении, то путь к файлу расширение будет сделано слишком.Вам нужно заключить переменные в кавычки, чтобы получить желаемый результат:
Теперь разделение слов или расширение пути не будет выполнено, поэтому вы должны получить желаемый результат, т.е. нужный файл будет удален. Если любое имя файла начинается с
-
, то выполните:Вы можете спросить, почему нам не нужно заключать в кавычки переменные, когда они используются внутри
[[
, причина в том,[[
что этоbash
ключевое слово, которое обрабатывает внутреннее расширение переменной, сохраняя расширение литералом.Теперь пара моментов:
Вы должны перенаправить STDERR (
exec 2>errorfile
) передrm
командой, иначе[[ -s errorfile ]]
проверка выдаст ложные срабатыванияВы использовали
[ -s $errorfile ]
, вы используете расширение переменной$errorfile
, которое было бы NUL, даннаяerrorfile
переменная нигде не определена. Возможно, вы имели в виду, просто[ -s errorfile ]
на основе перенаправления STDERRЕсли переменная
errorfile
определена во время использования[ -s $errorfile ]
, она снова захлебнется вышеупомянутыми случаямиIFS
и смещается, потому что, в отличие от этого[[
,[
внутренне не обрабатываетсяbash
В более поздней части скрипта вы пытаетесь
cp
использовать уже удаленный файл (опять же без кавычек переменной), это не имеет никакого смысла, вы должны проверить этот патрон и внести необходимые исправления в зависимости от вашей цели.источник