Код, который вы разместили [[ ! -z $param ]] && echo "I am not zero"
, будет печатать I am not zero
, если параметр не установлен/не определен или пуст (в bash, ksh и zsh ).
Для также печатать, если параметр содержит только пробелы (удалить пробелы ), POSIXly (для более широкого диапазона оболочек):
[ -z "${param#"${param%%[! ]*}"}" ] && echo "empty"
Пояснение:
${param# … }
удаляет начальный текст. ${param%%[! ]*}
Конечным результатом всего расширения является удаление всех ведущих пробелов.
Этот расширенный результат проверяется, если его длина равна 0.
Следовательно, если проверка верна, переменная либо уже была пустой, либо содержала только пробелы внутри.
Эту концепцию легко распространить на другие типы символов. Чтобы также включить вкладки, поместите явную вкладку внутри выражения в квадратных скобках :
. [ -z "${param#"${param%%[! ]*}"}" ] && echo "empty"
или используйте переменную с удаленными символами, которые вам нужны:
var=$' \t' # in ksh, bash, zsh
[ -z "${param#"${param%%[!$var]*}"}" ] && echo "empty"
или вы можете использовать некоторое «выражение класса символов» POSIX (пробел означает пробел и табуляцию):
[ -z "${param#"${param%%[![:blank:]]*}"}" ] && echo "empty"
Q1. Что означает -print0, зачем это нужно?
Лучше всего начать с руководства. В терминале вы можете набрать man find
и получить хорошее описание. Как правило, вы также можете просто погуглить «найти человека» и найти те же / похожие страницы руководств в Интернете.
В руководстве по поиску говорится о-print0
:
print the full file name on the standard output, followed by a null character (instead of the newline character that -print uses). This allows file names that contain newlines or other types of white space to be correctly interpreted by programs that process the find output.
Таким образом, это записывает каждое имя файла, за которым следует нулевой символ, и xargs с -0
будут считываться, ожидая, что каждый элемент будет заканчиваться на -0
. Это позволяет именам файлов содержать символ новой строки.
Q2.Почему /bin/ ? почему бы просто не rm -f ?
Из вашего вопроса непонятно, почему это было сделано.
Похоже, для этого нет веских причин. Иногда это делается для того, чтобы позволить вам запустить комментарий, когда переменная окружения PATH установлена неправильно. Это может быть обычным явлением при запуске команд в cron
.
Однако в данном случае это ничему не помогает, так как другие команды(find
иxargs
)не являются полными. Должно быть:
/bin/find ~ -name delete_me -type f -print0 | /usr/xargs -0 /bin/rm -f
Единственная другая (весьма маловероятная )причина может заключаться в том, что в вашей системе каким-то образом есть две разные rm
команды, и вам нужно указать, какая именно. Но это действительно очень маловероятно.
В3. Как изменить его так, чтобы он также находил и удалял все соответствующие файлы в подкаталогах?
Он уже делает это.
В4. Как изменить его так, чтобы он не находил в определенном каталоге?
Вы можете использовать опцию -prune
, чтобы пропустить этот каталог (и его дочерние ).
# Just editing your version...
find "$HOME" -name exclude_this_dir -prune -o -name delete_me -type f -print0 | xargs -0 /bin/rm -f
# More succinctly
find "$HOME" -name exclude_this_dir -prune -o -name delete_me -type f -exec rm -f {} +
Нестандартный -предикат -print0
означает «печатать путь к найденному файлу с завершающим нулевым символом в конце вместо символа новой строки». Это сделано для того, чтобы иметь возможность обрабатывать имена файлов, содержащие символы новой строки (, что разрешено в системах Unix; Однако символы nul не могут быть частью имени файла Unix ). Команда, читающая вывод команды find
, которая использует -print0
, должна знать, что записи завершаются нулем -. Это опция -0
для xargs
, которая позволяет читать записи с нулевым завершением -.
Не требуется. Ни один из
find "$HOME" -name delete_me -type f -delete
ни более стандартный
find "$HOME" -name delete_me -type f -exec rm {} +
использует -print0
. Обе команды делают то же самое, что и ваша команда, и их следует использовать вместо xargs
. Утилита xargs
может оказаться полезной при чтении аргументов из файла или какой-либо другой команды. При использовании find
безопаснее использовать встроенное средство -exec
. Там есть несколько вещей, которые некоторые реализации xargs
могут делать, но -exec
не могут, например запуск параллельных пакетов утилит. Однако в данном упражнении он не используется.
Также предпочтительнее использовать "$HOME"
вместо ~
в сценариях оболочки, поскольку $HOME
ведет себя как переменная, а ~
— нет.
Также обратите внимание, что опция -f
для rm
, вероятно, не нужна. Он используется, чтобы избежать сбоя утилиты rm
(с диагностическим сообщением и не -нулевым статусом выхода ), если указанные пути отсутствуют или если rm
вызывается без пути для удаления. Он также переопределяет все более ранние-i
(параметры интерактивного режима ). Но здесь нет опции -i
в командной строке rm
,и данные пути гарантированно существуют, так как find
используется для их поиска (, исключая условия гонки, когда файлы фактически удаляются во время выполнения find
каким-либо другим процессом между тем, когда они были найдены find
и удаляется rm
, выполненным из find
).
Нет причин использовать rm
с полным путем, за исключением случаев, когда нельзя гарантировать, что значение переменной PATH
содержит разумный набор путей к утилитам. Ненормально иметь сломанный PATH
, и сценарии написания, которые используют абсолютные пути для утилит, склонны ломаться, когда они перемещаются в другие системы.
Он уже выполняет рекурсию во все подкаталоги вашего домашнего каталога.
Удалите каталог, который вы хотите исключить из дерева поиска. Например, чтобы избежать всех каталогов с именемavoid
:
find "$HOME" -name avoid -prune -o -name delete_me -type f -exec rm {} +
Обратите внимание, что мы не можем использовать здесь -delete
, так как это подразумевает -depth
, то есть поиск в глубину -сначала. При первом поиске в глубину -мы посетим все подкаталоги и файлы внутри avoid
, прежде чем заметим, что каталог avoid
должен быть удален из дерева поиска.
Другой пример :Не входить в определенный каталог $HOME/dir/save_me
:
find "$HOME" -path "$HOME/dir/save_me" -prune -o -name delete_me -type f -exec rm {} +