通过读取文件名来移动文件到不同的目录

通过读取文件名来移动文件到不同的目录

我需要通过读取文件名来移动文件。我必须移动系统生成的文件,并且名称包含时间戳。我需要通过按月读取文件名来移动文件。

如果文件名包含201601*.txt,则移动到2016/January目录。如果文件名包含201602*.txt则移动到2016/February目录等。

答案1

好吧,如果日期字符串位于文件名中并且所有文件都位于同一目录中,您可以执行以下操作:

mv 201601*.txt 2016/January

手动执行此操作 12 次会很痛苦,因此我将创建一个包含数字和相应月份名称的列表:

$ paste <(printf '%s\n' {01..12}) <(cal 2016 | grep -Po '\s+\K[A-Z]\w{2,}') 
01  January
02  February
03  March
04  April
05  May
06  June
07  July
08  August
09  September
10  October
11  November
12  December

然后解析它来构建mv命令:

$ paste <(printf '%s\n' {01..12}) <(cal 2016 | grep -Po '\s+\K[A-Z]\w{2,}') | 
    while read num month; do echo mv "*2016$num*" 2016/"$month"; done
mv *201601* 2016/January
mv *201602* 2016/February
mv *201603* 2016/March
mv *201604* 2016/April
mv *201605* 2016/May
mv *201606* 2016/June
mv *201607* 2016/July
mv *201608* 2016/August
mv *201609* 2016/September
mv *201610* 2016/October
mv *201611* 2016/November
mv *201612* 2016/December

一旦您确定它满足您的需要,请删除echo以实际移动文件:

paste <(printf '%s\n' {01..12}) <(cal 2016 | grep -Po '\s+\K[A-Z]\w{2,}') | 
    while read num month; do echo mv "*2016$num*" 2016/"$month"; done

解释

将使用 Perl 兼容正则表达式 ( )grep -Po '\s+\K[A-Z]\w{2,}')运行,并且仅打印每行 ( ) 的匹配部分。使用的正则表达式将查找一个或多个空白字符 ( ),后跟一个大写字母 ( ) 和 2 个或多个单词字符 ( )。意思是“忽略在此之前的所有内容”,这将导致命令仅打印匹配字符串的部分grep-P-o\s+[A-Z]\w{2,}\K空白。整个过程只是打印月份列表。

答案2

兹什有一个很好的函数可以根据名称模式重命名文件:zmv。在替换模式中,$f指定整个原始名称$1$2等是括号内的组。使用数组来存储月份名称。

autoload -U zmv
months=(January February March April May June July August September October November December)
zmv '(2016)(<1-12>)*.txt' '$1/$months[$2]/$f'

因为这里的模式很简单,所以使用循环将其适应 bash 和 ksh 并不是很痛苦。您需要注意一些事情:从月份数字中去掉前导 0,这样它就不会被解释为八进制;数组索引从 0 开始。

months=(January February March April May June July August September October November December)
for f in 2016[0-9][0-9]*; do
  y=${f:0:4} m=${f:4:2}
  mv -- "$f" "$y/${months[${m#0}]}/$f"
done

另一种方法是 Perl 重命名脚本(或者Debian版本或者Unicode::争斗版本)。

rename 'BEGIN {@months = qw(January February March April May June July August September October November December)}
        s!^([0-9]{4})([0-9]{2})!$1/$months[$2]/&!' 2016[0-9][0-9]*

答案3

下面是一个bash遍历文件的解决方案,移动那些与组件匹配的文件(对于2000-2099 范围内yyyymm的值):yyyy

months=('' January February March April May June July August September October November December)

for f in 20[0-9][0-9][0-3][0-9]*
do
    year=$(echo "$f" | grep -Po '^20\d\d')           # Extract the four digit year, 20nn
    mm=$(echo "$f" | grep -Po '^(?<=20\d\d)\d\d')    # Find the two digit month number 01-12
    month=${months[$mm]}                             # Convert to a month name

    test -n "$year" -a -n "$month" && echo mv "$f" "$yyyy/$month/$f"
done

当您准备好运行时,请删除echo前缀。mv


如果您知道所有文件都以以下开头,2016则可以稍微简化处理:

for f in 2016[0-3][0-9]*
do
    mm=$(echo "$f" | grep -Po '^(?<=2016)\d\d')    # Find the two digit month number 01-12
    month=${months[$mm]}                           # Convert to a month name

    test -n "$month" && echo mv "$f" "2016/$month/$f"
done

相关内容