Непосредственная проблема заключается в том, что f
задается только для имени файла, а не для всего пути.То есть, если / tmp / testFolder содержит файл с именем example.txt, для f
будет установлено значение «example.txt», поэтому if [ -d $f ]; then
проверяет файл с именем «example.txt» в текущем рабочем каталоге., не в / tmp / testFolder.Один из вариантов - использовать if [ -d $dirPath/$f ]; then
, но есть и лучший способ.
Как правило, вы не должны анализировать вывод ls
, поскольку его вывод неоднозначен внесколько путей.Чтобы получить список файлов в определенном каталоге, просто используйте dirpath/*
- он получает список подходящих файлов без каких-либо проблем с неоднозначностью или синтаксическим анализом, которые будут у вас с ls
.Бонус: он включает указанный путь как часть результата (например, /tmp/testFolder/*
может дать "/tmp/testFolder/example.txt").
Другое предложение: вы должны (почти) всегда ставить переменнуюссылки в двойных кавычках, например "$f"
вместо просто $f
.
Исправление всего этого дает:
for f in "$dirPath"/*; do # Note that $dirPath should be quoted, but * cannot be
echo "$f out of if"
if [ -d "$f" ]; then
echo "$f is a directory"
fi
if [ -f "$f" ]; then
echo "$f is a file"
fi
done
Обратите внимание, что команды echo
также дадут полныйдорожка.Если вы этого не хотите, вы можете либо использовать команду basename
, чтобы получить только часть имени, например, f_name="$(basename "$f")"
, либо (как указывалось @melpomene) использовать расширение "${f##*/}"
(которое урезается до последнего«/» в переменной):
for f in "$dirPath"/*; do
f_name="${f##*/}" # The quotes are not strictly needed in an assignment, but do no harm
echo "$f_name out of if"
if [ -d "$f" ]; then
echo "$f_name is a directory"
fi
if [ -f "$f" ]; then
echo "$f_name is a file"
fi
done
О, и есть один возможный недостаток использования подстановочного знака вместо ls
: он вернет необработанный подстановочный знак, если совпадений нет.В данном случае это не имеет значения, но для мест, где это происходит, вы можете либо запустить цикл с [ -e "$f" ] || continue
(т.е. пропустить цикл, если на самом деле там ничего нет), либо если вы используете bash (не просто универсальную оболочку) вы можете установить параметр оболочки nullglob
(shopt -s nullglob
).
Еще одна рекомендация: shellcheck.net хорош для выявления распространенных ошибок сценариев, поэтому я рекомендую запускать ваши сценарии черезэто для предложений.