【问题标题】:Find file then cd to that directory in Linux在 Linux 中查找文件然后 cd 到该目录
【发布时间】:2010-08-11 12:57:13
【问题描述】:

在 shell 脚本中,我如何找到具有特定名称的文件,然后导航到该目录以对其进行进一步操作?

我将从这里将文件复制到另一个目录(但我已经可以这样做,只需将其添加到上下文中。)

【问题讨论】:

    标签: linux shell filesystems


    【解决方案1】:

    你可以使用类似的东西:

    pax[/home/pax]> cd "$(dirname "$(find / -type f -name ls | head -1)")"
    pax[/usr/bin]> _
    

    这将找到第一个 ls 常规文件,然后切换到该目录。

    就每个位的作用而言:

    • 查找将从/ 开始并向下搜索,列出所有名为ls (-name ls) 的常规文件(-type f)。您还可以向 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]> _
    

    【讨论】:

    • 我认为您需要在 -type f-name ls 之间留一个空格。
    • @Ross:注意每个 $() 周围应该有双引号(否则您的脚本将失败,路径包含空格和其他特殊字符):cd "$(dirname "$(find / -type f-name ls | head -1)")"
    • 这是一个很好的观点,Gilles,已更新修复。我很少在我的文件规范中放置空格,因为我认为它们很可恶,但我意识到有些人喜欢它们,你是对的:代码应该处理它们。
    • 它仍然会在包含换行符的目录名称上中断。
    • 是的,会的,在文件名中使用换行符、退格符、制表符和其他有趣字符的人应该被打死,分成小块,然后将这些小块发射到最远的地方宇宙在各个星星的心中燃烧:-)
    【解决方案2】:

    以下应该更安全:

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

    优点:

    • 双破折号可防止解释以连字符开头的目录名称作为选项(find 不会生成此类文件名,但它无害,并且可能需要类似的结构)
    • -name-type 之前检查,因为后者有时需要stat
    • 不需要dirname,因为%h 说明符已经打印了目录名称
    • -quit 在找到第一个文件后停止搜索,因此不需要 head 这将导致脚本在包含换行符的目录名称上失败

    【讨论】:

    • 对我来说,这是最好的答案。在大多数情况下甚至可以缩短,并且可以遵循以下样式:1)使用 find 命令查找您需要的内容,例如$ find . -name *.xsd 2) 添加 printf 和 -quit $ find . -name *.xsd -printf "%h" -quit 3) 用 backtics 包围并输入 cd (如果不需要,则省略):$ cd `find . -name *.xsd -printf "%h" -quit`
    • -printf '%h' 部分使得这个命令实际上什么都不返回,即使有文件......不太清楚为什么
    • @JanVlcinsky 使用反引号而不是引号对我不起作用。它失败并说path/to/folder: Is a directory
    【解决方案3】:

    没有人建议定位(对于大树来说更快)?

    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)
    

    重击:

    cd $(dirname $(locate -l1 -r "/zoo.txt$"))
    

    【讨论】:

      【解决方案4】:

      基于this answer 的类似问题,其他有用的选择可能是使用 2 个命令,第一个是查找文件,第二个是导航到其目录:

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

      !! 是历史扩展,意思是“上一个命令”。

      【讨论】:

        【解决方案5】:

        扩展已经给出的答案,如果您想迭代地导航到find 找到的每个文件并在每个目录中执行操作:

        for i in $(find /path/to/search/root -name filename -type f)
        do (
          cd $(dirname $(realpath $i));
          your_commands;
        )
        done
        

        【讨论】:

        【解决方案6】:

        如果您只是查找文件然后将其移动到其他位置,只需使用 find 和 -exec

        find /path -type f -iname "mytext.txt" -exec mv "{}" /destination +;
        

        【讨论】:

        • 我刚刚遇到了类似的情况,我想重命名不同目录中同名文件的副本。 find 的 -execdir 选项对我有用:find . -name foo.txt -execdir mv "{}" bar.txt ";" 在找到它的每个目录中将 foo.txt 重命名为 bar.txt。
        【解决方案7】:
        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
        
        }
        

        【讨论】:

          【解决方案8】:

          就这样,是不是很优雅?

          cdf yourfile.py
          

          当然你需要先设置它,但你只需要这样做一次

          将以下行添加到您的 .bashrc 或 .zshrc 中,无论您使用什么作为 shell 初始化脚本。

          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}
          }
          

          【讨论】:

            【解决方案9】:

            如果它是您PATH 中的程序,您可以这样做:

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

            或在 Bash 中:

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

            使用更少的外部可执行文件。

            这不使用外部:

            dest=$(type -P ls); cd "${dest%/*}"
            

            【讨论】:

            • cd 在哪个 shell 中不需要引号? export d="foo bar"; mkdir "$d"之后:ksh -c 'cd $d'投诉cd: bad substitutionash -c 'cd $d' 抱怨:can't cd to foo; bash -c 'cd $d' 抱怨:cd: foo: Not a directory.
            • @Gilles:我可以发誓在 Bash 中工作。我将编辑我的答案。
            • 它不能在符合 POSIX 的 shell 中工作,cd 对通常的扩展规则没有特殊的豁免。而且您仍然缺少 dirname 参数周围的引号。
            【解决方案10】:

            如果您的文件仅在一个位置,您可以尝试以下操作:

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

            您可以使用 -exec 来调用 dirname 并使用 find 返回的路径(即 {} 占位符所在的位置)。这将改变目录。您还可以添加双与号 (&&) 以在 shell 更改目录后执行下一个命令。

            例如:
            cd "$(find ~/ -name need_to_find_this.rb -exec dirname {} \;)" && ruby need_to_find_this.rb

            它将查找该 ruby​​ 文件,切换到目录,然后从该文件夹中运行它。此示例假定 文件名是唯一的,并且由于某种原因,ruby 脚本必须从其目录中运行。如果文件名不是唯一的,您将获得许多传递给 cd 的位置,它会返回一个错误然后它不会更改目录

            【讨论】:

              【解决方案11】:

              试试这个。我创建了这个供我自己使用。

              cd ~
              touch mycd
              sudo chmod +x mycd
              nano mycd
              cd $( ./mycd search_directory target_directory )"
              
              if [ $1 == '--help' ]
               then
                  echo -e "usage: cd \$( ./mycd \$1 \$2 )"
                  echo -e "usage: cd \$( ./mycd search_directory target_directory )"
              else
                find "$1"/ -name "$2" -type d -exec echo {} \; -quit
                fi
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2014-03-03
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2023-03-21
                • 2015-12-29
                • 1970-01-01
                相关资源
                最近更新 更多