当前我正在使用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 "print version: cp %s %sn" "${filename}" "$(printf "%sn" "${filename}" | sed "s/^.*[/](category[^/]*)[/](.*[.]data)$//target_path/1_2/")"; done
find命令打印找到的文件名,每行一个。
读取-r文件名读取一行文本并将其存储到文件名量中。
查找…|同时读取-r filename时,将文件名列表(每行一个)写入管道。一次只能读取一个文件名。对于读取的每个文件名,执行while块中的命令。
sed命令将路径名/source_path/category1/001.data更改为/target_path/category1_001.data。
我尽力在下面的几行中解释sed的字符串参数,但如果你正在研究这些主题,你应该阅读:
- Sed-Bruce Barnett的介绍和教程
- 正则表达式
s/是搜索和替换sed命令,后面跟着3个元素:"s/regex pattern/replacement/flag"
^在最开始的时候意味着,行的开始。
表示任意一个字符。
*表示前面指定的字符为0或无穷多。
[/]表示一个字符,字符/。[]用于转义/,否则它被解释为正则表达式模式、替换和标志之间的分隔符。
Alltogether^.*[/],表示以任何零个或多个字符开头的一行。此起始序列必须以/结束。
[^/]表示一个字符,开头的^表示不是所列字符的一部分。因此,它意味着除了/之外的任何一个字符。
[abc]介于[]之间,表示一个字符:要么a要么b要么c。
正则表达式模式中遇到的第一个\(.*\)可以用替换的\1引用。正则表达式模式中遇到的第二个\(.*\)可以用替换的\2引用。等。如果没有\转义符,(表示单个字符(
,内容无法引用。
完成后,使用cp来有效复制文件:
find /source_path -name *.data | while read -r filename; do cp "${filename}" "$(printf "%sn" "${filename}" | sed "s/^.*[/](category[^/]*)[/](.*[.]data)$//target_path/1_2/")"; done