使用 find、sed 和 mv 递归查找和删除子目录名称中的字符

Find and remove a character in subdirectory names recursively with find, sed and mv

提问人:Terry Bishop 提问时间:11/9/2023 最后编辑:Terry Bishop 更新时间:11/10/2023 访问量:83

问:

我正在尝试递归删除子目录中的字符,但似乎无法确定正确答案。我正在运行 BSD,并希望使用 find、sed 和 mv 来实现这一点。我是脚本编写和使用 sed 的初学者,因此任何帮助将不胜感激。

我在不同的子目录中命名了目录

dir/foobar 01
    foobar 02
    foobar 03
dir2/foobar 01
     foobar 02
     foobar 03

我想删除每个目录名称中的 0

dir/foobar 1
    foobar 2
    foobar 3
dir2/foobar 1
     foobar 2
     foobar 3

我已经通过 find 和 sed 走到了这一步,但不知道如何合并 mv 命令

find . -type d -name "foobar 01" | sed 's/0//g'

这会打印正确的格式化,但没有 mv 命令,它不会做任何进一步的事情......

有没有办法对所有匹配的子目录使用一个命令来做到这一点,或者我必须单独处理每种情况?

谢谢。

命令行界面 zsh

评论

0赞 Gairfowl 11/9/2023
另一个值得一看的工具是 zmvautoload zmv; zmv '(dir*)/(foobar )0(*)' '$1/$2$3'

答:

0赞 user3402754 11/9/2023 #1

为此,您可以结合使用 find、sed 和 xargs 以递归方式重命名目录。

像这样的东西应该可以完成工作:

find . -type d -name "foobar 01" -print0 | xargs -0 -I {} sh -c 'mv "{}" "$(echo "{}" | sed "s/0//g")"'

以下是该命令的说明:

find . -type d -name "foobar 01" -print0:这用于查找所有名为“foobar 01”的目录(),并使用空字符()打印它们。null 字符用于处理名称中包含空格的目录。-type d-print0

xargs -0 -I {} sh -c '...':这将获取 (null 分隔的目录列表) 的输出,并将指定的命令应用于每个目录。是输入的占位符。find{}

mv "{}" "$(echo "{}" | sed "s/0//g")":这是针对找到的每个目录执行的命令。它使用 mv 重命名目录。该命令用于从目录名称中删除“0”字符。sed

评论

0赞 Terry Bishop 11/9/2023
谢谢你的回答。你能分解这个命令,以便我可以了解更多关于语法的信息吗?
0赞 user3402754 11/9/2023
@TerryBishop假设它对你有用是安全的吗?
0赞 Terry Bishop 11/9/2023
还没有。我可以在周末测试它。几个问题:sh -c 是做什么的?如何在实际执行之前测试此命令?
0赞 despinaur 11/9/2023 #2

希望我理解了你的问题,你有名为“foobar”的目录和子目录 01、02、03

以下是递归列出它们的方法:

for DIR in $(find . -maxdepth 2 -type d -name "*0*"); do echo "$DIR"; done

以下是处理后检查所需结果的方法:

for DIR in $(find . -maxdepth 2 -type d -name "*0*"); do echo "$DIR" | sed -E 's/0//g'; done

最后,这里是处理它们的命令:

for DIR in $(find . -type d -name "*0*"); do mv "$DIR" "$(echo "$DIR" | sed -E 's/0//g')"; done
enter code here

评论

0赞 Terry Bishop 11/9/2023
不,目录的名称“/dir/foobar 01”、“/dir/foobar 02”等中有一个空格。您可以直接从 CLI 运行这些命令吗?
0赞 despinaur 11/10/2023
是的,你可以尝试一下,但我相当确定它可能因为空间而不起作用......
0赞 dawg 11/9/2023 #3

既然你正在使用,你就可以使用递归球。zsh

鉴于:

% tree .
.
├── dir
│   ├── foobar 01
│   ├── foobar 02
│   ├── foobar 03
│   └── foobar 4
└── dir2
    ├── foobar 01
    ├── foobar 02
    ├── foobar 03
    └── foobar 2

11 directories, 0 files

您可以使用此递归 glob 来查找名称中带有 的目录并重命名它们。这还会测试重命名是否会擦除现有文件或目录:0

#!/bin/zsh
# ^ that path deponds on your system.

for fn in **/*0[0-9]*/; do
    nfn="${fn//0}"
    if [[ -e $nfn ]]; then  
        echo "$nfn already exists! NOT renaming $fn=>$nfn"
        continue 
    fi     
    echo "renaming: $fn=>$nfn"
    mv "$fn" "$nfn"
done    

结果:

% tree .
.
├── dir
│   ├── foobar 1
│   ├── foobar 2
│   ├── foobar 3
│   └── foobar 4
└── dir2
    ├── foobar 02
    ├── foobar 1
    ├── foobar 2
    └── foobar 3

11 directories, 0 files

如果在循环上方添加,则相同的脚本适用于 Bash。shopt -s globstar

评论

0赞 Terry Bishop 11/10/2023
我该如何处理该脚本?我该如何运行它?
0赞 dawg 11/10/2023
我会将 sheebang 添加到顶部。最简单的方法是将其保存在 txt 文件中,然后保存在作为目标目录根目录的目录中。这是一个如何。zsh that_txt_file
0赞 Terry Bishop 11/10/2023
好的,感谢您的更新。你知道我可以了解这个脚本语法的来源吗?因为所有的 **、{}、[] 和 $ 都让我头晕目眩......
0赞 Terry Bishop 11/13/2023
我设法尝试了这个,因为它非常优雅,经过一些研究,我非常了解它。唯一错误的是某些目录名称中有零,并且 sctript 也删除了它们。我还没有找到解决方案,你能帮忙吗?
0赞 Terry Bishop 11/13/2023
我的意思是父目录名称中有零。