В скрипте я использую, find
чтобы собрать некоторые файлы в текущем каталоге, как в
$ find . -name "*.h"
./foo.h
Теперь я бы хотел, чтобы он просто выводил foo.h
без ./
префикса. Я думал, что пустая строка ""
обозначает текущий каталог в командах оболочки. Но это дает:
$ find "" -name "*.h"
find: ftsopen: No such file or directory
Так что я был не прав. Теперь мой вопрос: когда / как / где / .. означает ли "пустая строка (?)" Текущий каталог в командах, которые ожидают имя файла или путь? Есть ли аккуратное и поучительное объяснение?
Дополнительный вопрос заключается в том, можно ли решить обнаруженную выше ничтожность выше, без манипулирования строками а-ля ${parameter#word}
или cut
или sed
?
find
имеет параметр -printf для управления отображением результатов.find . -name '*.h' -printf '%P\n'
удалит./
префикс Посмотрите, чтоfind . -name '*.h' -print
делает.-printf
опцию. FWIW,strings
на мою находку дает@(#)PROGRAM:find PROJECT:shell_cmds-175
?!?Ответы:
Давным-давно (в 7-м издании , 32V , 4.2BSD , 4.3BSD ) на уровне системных вызовов имя пути нулевой длины обозначало текущий рабочий каталог (при использовании для поиска; оно было запрещено при попытке создать или удалить файл или каталог). В System III было ошибкой использовать путь нулевой длины при любых обстоятельствах, и стандарт POSIX имеет следующее, что можно сказать о разрешении пути:
источник
dir/
в основном такой же, какdir/.
Ты можешь использовать:
Обратите внимание, что файлы в текущем каталоге, чье имя начинается с,
.
будут опущены, а файлы, чье имя начинается с,-
будут интерпретироваться как опцииfind
и вызывать хаос, поэтому это не является общим эквивалентомfind . …
.Отсутствие строки, заканчивающейся на "
/
" как части имени файла, подразумевает текущий каталог, но это не означает, что текущий каталог обозначается пустой строкой (что, возможно, не совпадает с отсутствием строки, хотя это может выглядеть одинаково при печати).источник
Как правило, пустая строка не обозначает текущий каталог, ни для команд оболочки, ни в системных вызовах. Это было на некоторых старых системах, но не на POSIX-совместимых системах .
Иногда вы можете найти программу, которая использует текущий каталог, когда вы передаете пустую строку, и программа ожидает имя каталога. Иногда это является преднамеренным, а иногда побочным эффектом добавления абсолютного пути к текущему каталогу, когда данная строка не начинается с косой черты.
Лучше всего было бы оставить
./
. Это не приносит никакого вреда.Если список файлов предназначен для
Обратите внимание, что это искажает некоторые имена файлов, содержащие переводы строк. Обычно это не проблема для потребления человеком, и вывод
find
не подходит для потребления программой, поскольку он неоднозначен. Если вы используете-print0
, который подходит для использования в программе, вам, вероятно, все равно не нужен./
префикс.Вы можете использовать
find * …
вместоfind . …
, но обратите внимание, чтоfind *
есть ряд дефектов, которые делают его непригодным в целом:.
опущен.
или ..`) опущены.-
(или файл с именем!
или(
...), оно будет интерпретировано как опция или предикатfind
.Первый пункт не имеет значения, исключает ли ваш фильтр текущий каталог. Во-вторых, вы можете использовать шаблоны
..?* .[!.]* *
для сопоставления всех файлов в текущем каталоге, но вам нужно проверить, соответствует ли каждый шаблон хотя бы одному файлу, и пропустить его, если это не так. Это возможно, но очень громоздко. Последний пункт - пробка. Так чтоfind *
может подойти для быстрого использования командной строки, но не используйте его в скрипте.Альтернативный подход состоит в том, чтобы использовать рекурсивное средство оболочки, например
Это должно быть активировано с помощью
shopt -s globstar
bash иset -o globstar
ksh93, и не существует в базовой оболочке POSIX, такой как dash. Точечные файлы не будут проходить по умолчанию; чтобы включить их, сначала сделайте globbing, а не игнорируйте точечные файлыshopt -s dotglob
в bash илиFIGNORE='@(.|..)'
в ksh93. Также, если совпадений нет, эта команда печатает шаблон; запуститеshopt -s nullglob
bash, чтобы вместо этого напечатать пустую строку, и используйте шаблон~(N)**/*.h
в ksh.В zsh рекурсивное сглаживание включено по умолчанию. Используйте спецификатор glob,
D
чтобы включить точечные файлы иN
напечатать пустую строку, если совпадений нет (по умолчанию zsh выдает ошибку, если шаблон не соответствует ни одному файлу). Вы можете использоватьprintf
как выше илиисточник
find *
новы для меня, а некоторые пугают!Я не могу вспомнить ни одного примера, где пустая строка обозначает текущий каталог
.
. Вы можете думать о таких вызовах, какls
, но это потому, чтоls
предполагается, что текущий каталог, если не задан параметр, и на самом деле он не будет принимать пустую строку:источник
PATH
компонентом.Существуют различные приемы, которые вы можете использовать, чтобы получить результаты поиска без ведущего
./
:Используйте
-printf
опцию поиска и скажите, чтобы она только печатала%f
. Смотритеman find
:Например:
Разобрать вывод:
@ Уловка Антона
Что касается вашего другого вопроса, пустая строка никогда не обозначает текущий каталог. Просто различные программы используют текущий каталог по умолчанию, поэтому, когда вы запускаете их без аргументов, они запускаются в текущем каталоге.
источник
find
. Или используйте,%P
чтобы только раздеться./
find * -name '*.h'
найдетеfoo/.bar.h
, но не.bar.h
в текущем каталоге.Если файлы находятся в текущем каталоге, вы можете просто использовать
ls
:Если вам нужны файлы в подкаталогах и вам просто нужно имя файла, вы можете сделать что-то вроде:
Есть команды, которые получат отсутствие строки в качестве текущего каталога, но в основном потому, что они получат текущий каталог по умолчанию, если ничего не введено.
.
Всегда обозначают текущую директорию (и..
родительский каталог)источник
find
решение удаляет все компоненты каталога