`find -name`使用`cp`进行正则表达式模式和文件名替换

时间:2016-04-04 07:04:50

标签: regex file shell cron find

目前我正在使用cron中的命令将*.data的副本从源路径复制到目标路径:

find /source_path -name *.data -exec cp {} /target_path \;

源结构是:

    /source_path/category1/001.data
    /source_path/category1/002.data
    /source_path/category2/003.data
    /source_path/category3/004.data
    /source_path/categorya/005.data
    /source_path/categoryb/006.data

在上述cron命令之后,目标将包含:

    /target_path/001.data
    /target_path/002.data
    /target_path/003.data
    /target_path/004.data
    /target_path/005.data
    /target_path/006.data

我需要一个单行解决方案来替换我当前的cron命令,以便在执行后,目标将包含:

    /target_path/category1_001.data
    /target_path/category1_002.data
    /target_path/category2_003.data
    /target_path/category3_004.data
    /target_path/categorya_005.data
    /target_path/categoryb_006.data

将子目录名称附加为目标文件名的前缀。

感谢。

1 个答案:

答案 0 :(得分:2)

选中此命令仅打印字符串:

$ find /source_path -name \*.data  | while read -r filename; do printf "print version: cp %s %s\n" "${filename}" "$(printf "%s\n" "${filename}" | sed "s/^.*[/]\(category[^/]*\)[/]\(.*[.]data\)$/\/target_path\/\1_\2/")"; done

find 命令打印找到的文件名,每行一个。

读取-r文件名读取一行文本并将其存储到 filename 变量中。

找到... |同时读取-r filename ,将每行一个文件名列表写入管道。一次只能读取一个文件名。对于读取的每个文件名,执行 while 块中的命令。

sed 命令将路径名 /source_path/category1/001.data 更改为 /target_path/category1_001.data

我尽力在下面的行中解释 sed 的字符串参数,但是如果你介入这些主题,你应该阅读:

s / 是搜索和替换sed命令,后面跟着3个元素:" s / regex pattern / replacement / flag"

^ 一开始就意味着,开始行。

表示任何一个字符。

* 表示之前指定的0或无限数量的字符。

[/]表示一个字符,字符 / 。 []用于转义 / ,否则会被解释为正则表达式替换标记之间的分隔符

全部 ^。* [/] ,表示以任何零个或多个字符开头的行。此起始序列必须以 / 结束。

[^ /]表示一个字符, ^ 在开始时表示不是列出的字符的一部分。因此,它表示除 / 之外的任何一个字符。

[abc]在[]之间,表示一个字符:要么是b要么是c。

正则表达式中遇到的第一个 \(。* \)可以在替换中 \ 1 引用正则表达式中遇到的第二个 \(。* \)可以通过替换中的 \ 2 引用。如果没有 \ 转义字符,表示单个字符(,并且无法引用内容。

完成后,使用 cp 来有效复制文件:

find /source_path -name \*.data  | while read -r filename; do cp "${filename}" "$(printf "%s\n" "${filename}" | sed "s/^.*[/]\(category[^/]*\)[/]\(.*[.]data\)$/\/target_path\/\1_\2/")"; done