$ find -exec cd => выдает ошибку: => find: 'cd': такого файла или каталога нет

8

Когда я запускаю эту команду, она работает:

$ find . -inum 888696 -exec ls '{}' \;
Conversation.pst  Outlook Data File  Outlook Data File.sbd  Trash      Unsent Messages
Inbox.pst     Outlook Data File.msf  Sent.pst       Trash.msf  Unsent Messages.msf

Однако при замене lsна cdнего не работает:

$ find . -inum 888696 -exec cd '{}' \;
find: cd’: No such file or directory

Я знаю, cdчто это bashвстроенный, поэтому я попробовал это, которое также не работает:

$ find . -inum 888696 -exec builtin cd '{}' \;
find: builtin’: No such file or directory

Как я могу использовать cdвместе с find -execкомандой?


ОБНОВИТЬ

Поэтому я пытаюсь использовать cdс в find -execтом , что имя каталога является странным один , который показывает на моем терминале , как что - то вроде ????.

user3405291
источник
1
Кстати, вы можете LC_ALL=C printf '%q\n' *напечатать имена ASCII для всех файлов в вашем текущем каталоге, по одному в строке (с изменением новой строки $'\n'или аналогичной).
Чарльз Даффи

Ответы:

15

-execОпция findвыполняет внешнюю утилиту, возможно , с некоторым параметром командной строки и другими аргументами.

Ваш Unix не предоставляет cdкак внешнюю утилиту, только как встроенную оболочку, поэтому findне может ее выполнить. По крайней мере , MacOS и Solaris действительно обеспечивают в cdкачестве внешней полезности.

Выполнение cdтаким способом будет мало или вообще бесполезно , кроме как для проверки того, является ли найденный путь findкаталогом, в который вы сможете cd. Рабочий каталог в вашей интерактивной оболочке (или как бы он ни вызывал find) в любом случае не изменится.

Связанные с:


Если у вас есть проблемы со странным или чрезвычайно трудным для ввода именем каталога, и вы хотите перейти в этот каталог, подумайте о создании символической ссылки на каталог, а затем cdв нее, используя вместо этого эту ссылку:

find . -inum 888696 -exec ln -s {} thedir ';'

Это создаст символическую ссылку с именем, thedirкоторая будет указывать на проблемный каталог. Затем вы можете изменить рабочий каталог с помощью

cd thedir

(если ссылка существует в текущем каталоге). Это позволяет избежать изменения каталога в любом случае. Другая идея заключается в том, чтобы переименовать каталог аналогичным образом find, но это не рекомендуется, если другая программа ожидает, что каталог будет иметь это конкретное имя.

Кусалананда
источник
Поэтому я намерен использовать cdс в find -execтом , что имена каталогов в некоторых странных символов , которые не показывают правильно на мой терминал.
user3405291
@ user3405291 Из вопроса не ясно, что вы ожидаете при запуске команды. Ожидаете ли вы изменить каталог в интерактивной оболочке?
Кусалананда
Да, я просто хочу cdв каталог с плохим именем, и я не могу cdвойти в него обычным способом.
user3405291
@ user3405291 Смотрите обновление.
Кусалананда
Что забавно, так /bin/cdэто результат POSIX ( pubs.opengroup.org/onlinepubs/9699919799/utilities/… ), где обычные встроенные функции должны быть доступны для exec (). Конечно, /bin/cdвероятно, не делает то, что хотят люди :-)
Стивен Харрис
7

findзапускает -execсаму команду, она не включает оболочку. Даже если это произойдет, изменение каталога будет сохраняться только до выхода из этой оболочки, сразу после cd.

Вам нужно будет передать имя файла в текущую оболочку cd. В зависимости от того, насколько плохи ваши имена файлов, вы можете использовать подстановку команд:

cd "$(find . -inum 888696)"

Это не сработает, если имя файла заканчивается на новой строке, так как подстановка команд пожирает завершающие символы новой строки. В этом случае вам нужно будет защитить символ новой строки и избавиться от findдобавленного при печати:

dir=$(find . -inum 888696; echo x)
cd "${dir%?x}"

Или, с помощью GNU find, он не должен печатать завершающий символ новой строки (но все равно защищать любой в имени файла):

dir=$(find . -inum 888696 -printf "%px" -quit)
cd "${dir%x}"

Также используя -quitпредикат (также расширение GNU), чтобы перестать смотреть на первое совпадение в качестве оптимизации.

В качестве альтернативы, вы можете запустить новую оболочку изнутри find, но это немного уродливо:

find . -inum 888696 -exec bash -c 'cd "$1" && exec bash' sh {} \;
ilkkachu
источник
Попробовал трюк с помощью "echo x", для каталогов, заканчивающихся символом новой строки, возвратом каретки и тем и другим, но безуспешно
Джерард Х. Пилле
@ GerardH.Pille, о, извините, я забыл, что findдобавляется сама новая строка при печати. Ред.
ilkkachu
Если вы замените printf на print0, вы можете сделать 'cd "$ dir"'.
Джерард Х. Пилле
@ GerardH. Пилл, возможно. Но Bash игнорирует любые нулевые байты во входных данных из подстановки команд и удаляет завершающий символ новой строки только после этого. Так dir=$(find -print0)что все равно будет
выбрасывать завершающий перевод
5

Не с exec, но этого может быть достаточно для вас:

cd "$(find . -inum 888696 -type d)"

«Тип d», просто чтобы быть уверенным. Что я не знаю.

Джерард Х. Пилле
источник
Это терпит неудачу, если имя каталога заканчивается новой строкой.
Кусалананда
Конечно, но каталоги редко. Если я пытаюсь создать его на linux ext4, я получаю «ошибку протокола». Тебе не кажется, что это пустая трата времени?
Джерард Х. Пилле
2
Ну, имена редко имеют непечатные символы, но этот, очевидно, есть.
Кусалананда
Какие файловые системы позволяют переводить строки в имена каталогов?
Джерард Х. Пилле
1
@ GerardH.Pille, как ты это проверил? mkdir $'foo\n'отлично работает здесь; Я еще не видел собственную файловую систему UNIX, где она не поддерживалась.
Чарльз Даффи
4

Используйте поток с разделителями NUL для чтения выходных данных, findкоторые работают во всех случаях, включая имена, заканчивающиеся символом новой строки. Кроме того, вы можете использовать printf '%q'для создания удобочитаемого представления имени файла.

inum=888696
if IFS= read -r -d '' filename < <(find . -inum "$inum" -print0); then
  LC_ALL=C printf 'Located filename: %q\n' "$filename" >&2
  cd -- "$filename"
else
  echo "No file located for inode $inum" >&2
fi
Чарльз Даффи
источник
3

Если вы получили это сообщение, значит, ваша платформа ОС глючит. Стандарт POSIX требует, чтобы именованная команда cdбыла доступна в файловой системе, чтобы ее можно было вызывать с помощью exec().

Теперь плохие новости для вас:

Даже если в вашей платформе ОС не было ошибок, вы просто не увидели предупреждение, но не получили ожидаемых результатов, поскольку это не поможет вам, если отдельная программа изменит свой текущий рабочий каталог и сразу же умрет после этого.

Если вы хотите иметь эффективную cdкоманду, выполняемую find, вы можете сделать что-то вроде:

find . -type d -exec sh -c 'cd "$1"; some other command' dummy {} \;
Шили
источник
2
Это только ошибка, если эта платформа заявляет о соответствии POSIX. Наличие автономной утилиты cd не очень полезно, поэтому имеет смысл игнорировать это требование, в противном случае это не повлияет на удобство использования платформы. Обратите внимание, что оставление расширения параметра без кавычек имеет особое значение sh, а не то, что вы хотели бы сделать. Лучше избегать фиктивных значений для этого встроенного скрипта, $0как это используется, например, в сообщениях об ошибках (например, когда это не cdполучится).
Стефан Шазелас
Вы имели в виду cd "$1"? Если имя сложно ввести, оно также может содержать метасимволы оболочки ...
Тоби Спейт
исправить это была опечатка
щил