Bash 使用prename或sed搜索和替换

Bash 使用prename或sed搜索和替换,bash,sed,file-rename,Bash,Sed,File Rename,我正在尝试按以下方式在文件名中执行搜索和替换: $ tree . ├── a_a │   ├── a_b_c │   ├── a b c.mkv │   ├── b_b │   └── b_c_d ├── b_a │   ├── a_f_r │   ├── c_d │   ├── f_r_e │   └── r r ├── c_r │   ├── d_f │   └── r_a_s.mkv └── d.mkv 我想用空格替换文件名和文件夹名中的下划线。我想这样做的方法是先替换内部目录中存在的文

我正在尝试按以下方式在文件名中执行搜索和替换:

$ tree
.
├── a_a
│   ├── a_b_c
│   ├── a b c.mkv
│   ├── b_b
│   └── b_c_d
├── b_a
│   ├── a_f_r
│   ├── c_d
│   ├── f_r_e
│   └── r r
├── c_r
│   ├── d_f
│   └── r_a_s.mkv
└── d.mkv
我想用空格替换文件名和文件夹名中的下划线。我想这样做的方法是先替换内部目录中存在的文件和文件夹的基本名称中的下划线,然后向上移动,这样我递归的路径在下一次迭代中仍然存在,因为如果我重命名上层目录,在下一次迭代中,访问其内部目录和文件的路径将变得无效

我知道我可以使用find命令递归文件。现在我想使用一个工具来执行替换操作,从内部文件开始,然后向外移动。我在编写正则表达式方面没有太多经验,但我认为我们可以使用正则表达式中的分组来完成这项工作,但我不确定是否需要帮助

到目前为止,我已经能够弄清楚,我们可以使用正则表达式组来访问文件名的某些部分。更具体地说,我们可以使用以下正则表达式获取文件夹和文件的基本名称:

rename -n 's!([^/]*\Z)!uc($1)!e' ./*
在重命名命令中使用上述正则表达式,我们可以将基本名称组转换为大写,我想知道如何将该组中的下划线替换为空格

另外,我知道你们中的一些人可能会说这是一个重复的问题,但请再读一遍,我在问这个问题之前做了很多研究,但在任何地方都找不到这个具体的问题

#!/bin/bash

# man find, search for -type
#
# these are other types:
# b - block special, c - character special, d - directory, p - named pipe
# f - regular file, l - symbolic link, s - socket

# Move directories first, then everything else
for TYPE in d f; do

    for NAME in $( find . -type $TYPE -print0 ); do
        if [[ $NAME =~ [a-z] ]]; then
            NEW_NAME=$NAME
            NEW_NAME=${NEW_NAME//[\_]/-} # Change '-' to ' ' if you insist on spaces
            echo "renaming '$NAME' to '$NEW_NAME'"
            mv "$NAME" "$NEW_NAME"
        fi
    done

done
备注:

  • -depth
    参数允许find首先遍历目录深度
  • dirname
    /
    basename
    -拆分可防止目录与其子目录一起重命名。一次只能重命名叶文件/目录
  • 在文件名(包括传入文件名)中允许空格的地方引用所有内容
备注:

  • -depth
    参数允许find首先遍历目录深度
  • dirname
    /
    basename
    -拆分可防止目录与其子目录一起重命名。一次只能重命名叶文件/目录
  • 在文件名(包括传入文件名)中允许空格的地方引用所有内容


请解释您的答案中使用的任何正则表达式。帮助他人在文件名中添加空格是不道德的。@webb,好吧,然后用破折号替换下划线:)@webb:虽然我也尽量避免使用空格,但没有理由不正确地逃逸。@tom idk学习正则表达式与要求使用单行脚本有什么关系(问题的解决方案显然不是1个regexp!)但我只是告诉你为什么要求一行代码通常被认为是负面的,我看到你现在已经取消了这一要求,祝你好运!请解释一下你的答案中使用的任何正则表达式。帮助别人在文件名中加空格是不道德的。@webb,好吧,那么用破折号替换下划线:)@webb:虽然我也尽量避免空格,不过,没有理由不正确地逃避。@tom idk了解regexp与要求一行脚本有什么关系(你的问题的解决方案显然不是1个regexp!),但我只是告诉你为什么要求一行脚本通常被认为是负面的,我看到你现在已经取消了这个要求,祝你好运!如果名称中可能包含空格,则必须像这样引用
mv
调用:
mv“$NAME”“$NEW\u NAME”
。而且,这个查找调用可能不适用于空格。这很公平。我决不是在提倡空间。我相信@webb说得最好!在mv和-print0中添加了引号以查找。添加
-print0
没有帮助。始终执行
find…| |而IFS=read-r file
而不是
查找$(find…
中的文件,然后可以查看
-print0
等。如果名称可能包含空格,则必须引用
mv
这样的调用:
mv“$NAME”“$NEW\u NAME”
。而且,这个查找调用可能不适用于空格。这很公平。我决不是在提倡空间。我相信@webb说得最好!在mv和-print0中添加了引号以查找。添加
-print0
没有帮助。始终执行
find…| |而IFS=read-r file
而不是
查找$(find…
中的文件,然后您可以查看
-print0
等。
#!/bin/bash
find -depth | while IFS= read -r fn; do
    pnew=$(dirname  "$fn") 
    fnew=$(basename "$fn") 
    if [[ "$fnew" =~ "_" ]]; then
        new="$pnew/${fnew//_/ }"
        echo "$fn -> $new"  
        mv "$fn" "$new"
    fi
done