Скрипт, который у меня есть, требует двух входных данных: один — , filepath
а другой — , filename
который используется для проверки существования файла с помощью команды find.
#!/bin/bash
Filepath=$1
Filename=$2
if [ -z "$Filepath" ] && [ -z "$Filename" ]
then
echo "Requires Input"
elif [ ! -z "$Filepath" ] && [ ! -z "$Filename" ]
then
Found=`find "$Filepath" -iname "$Filename"`
if [ -z "$Found" ]
then
echo "Not Found"
else
echo $Found
fi
fi
Это работает совершенно нормально, как и ожидалось. Позже мне пришлось добавить еще пару условий в этот скрипт, то есть если мы получаем только в filename
качестве входного параметра, то мы должны искать этот файл во всей файловой системе, как показано ниже
find / -iname "$Filename"
А в случае, если filepath
в этот скрипт передается только входной параметр, то он должен вывести, что параметр имени файла также обязателен или просто должен быть выведен.
решение1
Я бы сделал:
#! /bin/sh -
pattern=${1?Please provide a file name}
shift
[ "$#" -gt 0 ] || set /
find "$@" -iname "$pattern" | grep '^' && exit
echo >&2 "Not found"
exit 1
То есть, пройтиимя(обратите внимание, что find
обрабатывает его как (нечувствительный к регистру из-за -iname
) шаблон для сопоставления с именами файлов, а не как точное имя файла для поиска) в качестве первого аргумента. Любые другие аргументы — это каталоги или файлы для поиска, и если ни один из них не указан, поиск в /
.
Вместо того, чтобы сохранять вывод в переменной и отображать его в конце, используйте его grep
в качестве сквозного метода, который возвращает значение true, если файл найден.
Кроме того, я вывожу сообщение «Не найдено» на stderr вместо stdout и сообщаю о невозможности найти файл в статусе выхода.
Как отметил @ThomasN, есть обычная проблема, что вы не можете надежно передавать имена файлов/каталогов в find
. Если вы хотите выполнить поиск в каталоге с именем -delete
, вызов, that-script name -delete
например, будет иметь катастрофические последствия. В BSD find
это можно обойти, выполнив (перед вызовом find
):
for i do
set -- "$@" -f "$i"
shift
done
Для переносимости (хотя имейте в виду, что это -iname
непереносимо) вам придется добавлять ./
относительные пути, что может быть проблематично, например:
for i do
case $i in
(. | ./* | /*) ;; # /foo, ./foo are not a problem
(*) i=./$i
esac
set -- "$@" "$i"
shift
done
find "$@"...
Однако это влияет на вывод (как вы увидите ./delete/name
вместо -delete/name
).