Найдите файл, затем перейдите в этот каталог в Linux - PullRequest
19 голосов
/ 11 августа 2010

В сценарии оболочки, как мне найти файл по определенному имени и затем перейти в этот каталог для дальнейших операций с ним?

Отсюда я собираюсь скопировать файл в другой каталог (но я могу сделать это, просто добавив его для контекста.)

Ответы [ 10 ]

21 голосов
/ 11 августа 2010

Вы можете использовать что-то вроде:

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]> _
10 голосов
/ 12 августа 2010

Следующие параметры должны быть более безопасными:

cd -- "$(find / -name ls -type f -printf '%h' -quit)"

Преимущества:

  • Двойная черта предотвращает интерпретацию имени каталога, начинающегося с дефиса как опции (find не производит такие имена файлов, но это не вредно и может потребоваться для аналогичных конструкций)
  • -name проверка перед проверкой -type, поскольку последняя иногда требует stat
  • Нет dirname требуется, потому что спецификатор %h уже печатает имя каталога
  • -quit, чтобы остановить поиск после первого найденного файла, таким образом, head не требуется, что приведет к сбою сценарияимена каталогов, содержащие переводы строк
4 голосов
/ 12 февраля 2016

никто не предлагает найти (что намного быстрее для огромных деревьев)?

zsh:

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$"))
3 голосов
/ 17 июня 2014

Исходя из этого ответа на аналогичный вопрос, другим полезным выбором может быть наличие 2 команд: 1-й для поиска файла и 2-й для перехода к его каталогу:

find ./ -name "champions.txt"
cd "$(dirname "$(!!)")"

Где !! - расширение истории, означающее «предыдущая команда».

1 голос
/ 01 марта 2013

Расширение уже полученных ответов, если вы хотите итеративно переходить к каждому файлу, который find находит и выполняет операции в каждом каталоге:

for i in $(find /path/to/search/root -name filename -type f)
do (
  cd $(dirname $(realpath $i));
  your_commands;
)
done
1 голос
/ 11 июля 2012
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

}
1 голос
/ 11 августа 2010

если вы просто находите файл и затем перемещаете его в другое место, просто используйте find и -exec

find /path -type f -iname "mytext.txt" -exec mv "{}" /destination +;
0 голосов
/ 21 июля 2015

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

cd "$(find ~/ -name [filename] -exec dirname {} \;)" && ...

Вы можете использовать -exec, чтобы вызвать dirname с путем, который возвращает находка (который идет там, где заполнитель {}).Это изменит каталоги.Вы также можете добавить двойные амперсанды (&&) для выполнения следующей команды после того, как оболочка изменила каталог.

Например:
cd "$(find ~/ -name need_to_find_this.rb -exec dirname {} \;)" && ruby need_to_find_this.rb

Он будет искать этот рубинфайл, перейдите в каталог, затем запустите его из этой папки.В этом примере предполагается, что имя файла уникально и что по какой-то причине скрипт ruby ​​должен запускаться из своего каталога.Если имя файла не уникально, вы получите много мест, переданных на cd, он вернет ошибку, тогда не изменит каталоги .

0 голосов
/ 29 августа 2014

Просто так, разве это не элегантно?

cdf yourfile.py

Конечно, сначала нужно настроить его, но вам нужно сделать это только один раз :

Добавьте следующую строку в ваш .bashrc или .zshrc, что бы вы ни использовали в качестве сценария инициализации оболочки.

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}
}
0 голосов
/ 11 августа 2010

Если это программа в вашем PATH, вы можете выполнить:

cd "$(dirname "$(which ls)")"

или в Bash:

cd "$(dirname "$(type -P ls)")"

, которая использует на один внешний исполняемый файл меньше.

Это не использует внешние:

dest=$(type -P ls); cd "${dest%/*}"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...