Найти файл, затем 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, оно вернет ошибку, а затем не изменит каталоги.