`find -name`与regex模式和文件名替换使用`cp` [英] `find -name` with regex pattern and filename replacement using `cp`

查看:204
本文介绍了`find -name`与regex模式和文件名替换使用`cp`的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目前我使用 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

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



感谢。

解决方案

检查此命令只打印字符串:

  $ find / source_path -name \ * .data | while read -r filename; do printf打印版本:cp%s%s\\\
$ {filename}$(printf%s\\\
$ {filename}| seds /^.*[/] \\(category [^ /] * \)[/] \(。* [。] data \)$ / \ / target_path\ / \1_\2 /) done

find 命令打印找到的文件名, p>

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



find ... |同时读取-r filename ,将一行文件名列表写入管道。一次只能读取一个文件名。



sed 命令会更改路径名称 strong> /source_path/category1/001.data 键入 /target_path/category1_001.data



sed 的字符串参数,但如果您在这些主题中介入,您应该阅读:





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



^ 在开始时表示行的开头。



任何一个字符。



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



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



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



[^ /]表示一个字符, ^ 部分的char列出。因此,它表示除 / 之外的任何一个字符。



[abc]介于[]之间,表示一个字符: 。



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

完成后使用 cp 可有效地复制文件:

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


Currently I'm using the command in cron to make copy of *.data from source to target path:

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

The source structure is:

    /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

After the above cron command, the target will contain:

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

I need a one-line solution to replace my current cron command, so that after execution, the target will contain:

    /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

To append sub-directory name as a prefix of the target filename.

Thanks.

解决方案

Check this command which only prints strings:

$ 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 command prints the filenames found, one per line.

read -r filename read one line of text and store it into filename variable.

find ... | while read -r filename all together, write a list of filenames, one per line, into the pipe. Only one filename is read at a time. For each filename read, the command into the while block is executed.

The sed command changes a pathname /source_path/category1/001.data into /target_path/category1_001.data.

I tried my best to explain the string argument of sed in the lines below, but if you are interresting in these topics you should read:

s/ is the search and replace sed command and it is followed with 3 elements: "s/regex pattern/replacement/flag"

^ at the very start means, start of the line.

. means any one char.

* means 0 or infinite number of the char specified just before.

[/] means one char, the char /. [] are used to escape / otherwise it is interpreted as a delimiter between regex pattern, replacement, and flag.

Alltogether ^.*[/], means a line starting with any zero or more chars. This starting sequence must end with /.

[^/] means one char, ^ at start means not part of the char listed. So, it means any one char except the /.

[abc] between [], means one char: either a either b either c.

The first \(.*\) encountered in the regex pattern can be referenced with \1 in replacement. The second \(.*\) encountered in the regex pattern can be referenced with \2 in replacement. etc. Without \ escape char, ( means a single char (, and the content cannot be referenced.

When done use cp instead to effectively copy the files:

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

这篇关于`find -name`与regex模式和文件名替换使用`cp`的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆