Найти файл, затем cd, в этот каталог в Linux
В оболочке script как я могу найти файл по определенному имени, а затем перейти к этому каталогу для выполнения дальнейших операций над ним?
Отсюда я собираюсь скопировать файл в другой каталог (но я могу сделать это, просто добавив его в контекст.)
Ответы
Ответ 1
Вы можете использовать что-то вроде:
pax[/home/pax]> cd "$(dirname "$(find / -type f -name ls | head -1)")"
pax[/usr/bin]> _
Здесь будет найден первый обычный файл ls
, затем изменится на этот каталог.
В терминах каждого бит:
- Поиск будет начинаться с
/
и искать вниз, перечисляя все обычные файлы (-type f
), называемые ls
(-name ls
). Есть другие вещи, которые вы можете добавить в find
, чтобы дополнительно ограничить файлы, которые вы получаете.
- Трубопровод через
head -1
будет отфильтровывать все, кроме первого.
-
$()
- это способ вывода вывода команды и поместить ее в командную строку для другой команды.
-
dirname
может взять полную спецификацию файла и дать вам бит пути.
-
cd
просто изменяет этот каталог.
Если вы выполняете каждый бит в последовательности, вы можете видеть, что происходит:
pax[/home/pax]> find / -type f -name ls
/usr/bin/ls
pax[/home/pax]> find / -type f -name ls | head -1
/usr/bin/ls
pax[/home/pax]> dirname "$(find / -type f -name ls | head -1)"
/usr/bin
pax[/home/pax]> cd "$(dirname "$(find / -type f -name ls | head -1)")"
pax[/usr/bin]> _
Ответ 2
Следующее должно быть более безопасным:
cd -- "$(find / -name ls -type f -printf '%h' -quit)"
Преимущества:
- Двойная тире предотвращает интерпретацию имени каталога, начиная с дефиса в качестве опции (
find
не создает такие имена файлов, но это не вредно и может потребоваться для подобных конструкций)
-
-name
проверить перед -type
проверить, потому что последнему иногда требуется stat
- Нет
dirname
, потому что спецификатор %h
уже печатает имя каталога
-
-quit
, чтобы остановить поиск после первого найденного файла, поэтому не требуется head
, что приведет к сбою script в именах каталогов, содержащих символы новой строки
Ответ 3
Основываясь на этом ответе на аналогичный вопрос, другой полезный выбор может состоять из двух команд: 1-го, чтобы найти файл, а второй - для его каталога:
find ./ -name "champions.txt"
cd "$(dirname "$(!!)")"
Где !!
- расширение истории, означающее "предыдущая команда".
Ответ 4
если вы просто находите файл, а затем перемещаете его в другом месте, просто используйте find и -exec
find /path -type f -iname "mytext.txt" -exec mv "{}" /destination +;
Ответ 5
function fReturnFilepathOfContainingDirectory {
#fReturnFilepathOfContainingDirectory_2012.0709.18:19
#$1=File
local vlFl
local vlGwkdvlFl
local vlItrtn
local vlPrdct
vlFl=$1
vlGwkdvlFl=`echo $vlFl | gawk -F/ '{ $NF="" ; print $0 }'`
for vlItrtn in `echo $vlGwkdvlFl` ;do
vlPrdct=`echo $vlPrdct'/'$vlItrtn`
done
echo $vlPrdct
}
Ответ 6
никто не предлагает найти (что намного быстрее для огромных деревьев)?
ЗШ:
cd $(locate zoo.txt|head -1)(:h)
cd ${$(locate zoo.txt)[1]:h}
cd ${$(locate -r "/zoo.txt$")[1]:h}
or could be slow
cd **/zoo.txt(:h)
bash:
cd $(dirname $(locate -l1 -r "/zoo.txt$"))
Ответ 7
Если это программа в вашем PATH
, вы можете сделать:
cd "$(dirname "$(which ls)")"
или в Bash:
cd "$(dirname "$(type -P ls)")"
который использует один внешний исполняемый файл.
Это не использует внешние символы:
dest=$(type -P ls); cd "${dest%/*}"
Ответ 8
Расширение ответов уже задано, если вы хотите последовательно перемещаться по каждому файлу, который find
находит и выполняет операции в каждом каталоге:
for i in $(find /path/to/search/root -name filename -type f)
do (
cd $(dirname $(realpath $i));
your_commands;
)
done
Ответ 9
Просто так, разве это не элегантно?
cdf yourfile.py
Конечно, сначала нужно настроить его, но вам нужно сделать это только один раз:
Добавьте следующую строку в ваш .bashrc или .zshrc, что бы вы ни использовали в качестве инициализации вашей оболочки script.
source ~/bin/cdf.sh
И добавьте этот код в файл ~/bin/cdf.sh, который вам нужно создать с нуля.
#!/bin/bash
function cdf() {
THEFILE=$1
echo "cd into directory of ${THEFILE}"
# For Mac, replace find with mdfind to get it a lot faster. And it does not need args ". -name" part.
THEDIR=$(find . -name ${THEFILE} |head -1 |grep -Eo "/[ /._A-Za-z0-9\-]+/")
cd ${THEDIR}
}
Ответ 10
Если ваш файл находится только в одном месте, вы можете попробовать следующее:
cd "$(find ~/ -name [filename] -exec dirname {} \;)" && ...
Вы можете использовать -exec
для вызова dirname
с помощью пути, который возвращает return (который находится там, где находится заполнитель {}
). Это изменит каталоги. Вы также можете добавить двойные амперсанды (&&
), чтобы выполнить следующую команду после того, как оболочка изменила каталог.
Например:
cd "$(find ~/ -name need_to_find_this.rb -exec dirname {} \;)" && ruby need_to_find_this.rb
Он будет искать этот рубиновый файл, перейти в каталог, а затем запустить его из этой папки. В этом примере предполагается, что имя файла уникально, и по какой-то причине ruby script должен запускаться из своего каталога. Если имя файла не уникально, вы получите много адресов, переданных на cd, оно вернет ошибку, а затем не изменит каталоги.