在一个shell脚本中,我如何根据特定文件名查找文件并导航到该目录以进行进一步操作?
从这里开始,我将把该文件复制到另一个目录(但是我已经可以做到这一点,只是为了提供上下文而添加这个问题)。
从这里开始,我将把该文件复制到另一个目录(但是我已经可以做到这一点,只是为了提供上下文而添加这个问题)。
你可以像这样使用:
cd -- "$(dirname "$(find / -type f -name ls | head -1)")"
这个命令会定位到第一个ls
正则文件,然后转到该目录。
关于每个部分的作用:
find
从根目录/
开始向下搜索,列出所有正则文件(-type f
),名为ls
(-name ls
)。您可以添加其他内容来进一步限制要获取的文件。| head -1
将过滤除了第一行之外的所有内容。$()
是将一个命令的输出放在另一个命令的命令行上的一种方法。dirname
可以接受完整的文件路径,并给您路径部分。cd
只是更改为该目录,--
用于防止以连字符开头的目录名被视为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]> _
cd -- "$(find / -name ls -type f -printf '%h' -quit)"
优点:
find
不会生成这样的文件名,但它并非有害且可能需要类似的构造)-name
检查在 -type
检查之前,因为后者有时需要一个 stat
dirname
,因为 %h
指示符已经打印出目录名称-quit
可以在找到第一个文件后停止搜索,因此不需要 head
,从而避免脚本在包含换行符的目录名上失败`$ find . -name *.xsd`
2)添加printf和-quit参数`$ find . -name *.xsd -printf "%h" -quit`
3)用反引号括起来并输入cd(如果不需要则忽略--):`$ cd \`find . -name *.xsd -printf "%h" -quit\``
- Jan Vlcinsky-printf '%h'
这部分使得该命令实际上不返回任何内容,即使有文件存在...不太确定为什么。 - phil294cd $(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$"))
基于这个答案给出的类似问题的解决方案,另一个有用的选择是使用两个命令,第一个用于查找文件,第二个用于进入其目录:
find ./ -name "champions.txt"
cd "$(dirname "$(!!)")"
在IT技术中,“!!”是历史扩展的意思,表示“上一个命令”。
进一步补充之前的回答,如果您想迭代地浏览每个find
定位到的文件,并在每个目录中执行操作:
for i in $(find /path/to/search/root -name filename -type f)
do (
cd $(dirname $(realpath $i));
your_commands;
)
done
find
循环,因为它们容易出错:https://github.com/koalaman/shellcheck/wiki/SC2044 - MakisHfunction 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
}
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}
}
find /path -type f -iname "mytext.txt" -exec mv "{}" /destination +;
find
的 -execdir
选项对我很有帮助:find . -name foo.txt -execdir mv "{}" bar.txt ";"
可以在每个发现它的目录中将foo.txt重命名为bar.txt。 - Andrew HershbergerPATH
中的一个程序,你可以这样做:cd "$(dirname "$(which ls)")"
或者在Bash中:
cd "$(dirname "$(type -P ls)")"
这个使用一个较少的外部可执行文件。
这个不使用任何外部文件:
dest=$(type -P ls); cd "${dest%/*}"
cd
命令不需要引号?在执行 export d="foo bar"; mkdir "$d"
后,ksh -c 'cd $d'
报错 cd: bad substitution
;ash -c 'cd $d'
报错 can't cd to foo
;bash -c 'cd $d'
报错 cd: foo: Not a directory
。 - Gilles 'SO- stop being evil'cd
没有特殊规定来遵循通常的扩展规则。而且你仍然缺少对dirname
参数周围的引号。 - Gilles 'SO- stop being evil'如果您的文件只在一个位置,您可以尝试以下操作:
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,它将返回错误,然后不会更改目录。
$()
周围应该有双引号(否则您的脚本将无法处理包含空格和其他特殊字符的路径):cd "$(dirname "$(find / -type f-name ls | head -1)")"
。 - Gilles 'SO- stop being evil'