【问题标题】:Rename files using sed and mv使用 sed 和 mv 重命名文件
【发布时间】:2011-08-06 00:27:30
【问题描述】:

我想重命名文件的格式:

img_MM-DD-YY_XX.jpg

img_MM-DD-YY_XXX.jpg

到:

newyears_YYYY-MM-DD_XXX.jpg

地点:

  • YYYY = 年
  • MM = 月
  • DD = 天
  • XXX 或 XX = 照片编号

我想出了这个脚本,但它不起作用:

for filename in ?*.jpg; do
        newFilename=$(echo $filename | \
        sed 's/img_\(.*\)-\(.*\)-\(.*\)_\([0-9][0-9]\)\./newyears_20\3-\1-\2_0\4./;
                s/img_\(.*\)-\(.*\)-\(.*\)_\([0-9][0-9][0-9]\)/newyears_20\3-\1-\2_\4/' -)
        mv $filename $newFilename
done

任何帮助将不胜感激。

【问题讨论】:

  • 运行脚本时会发生什么? for filename in ?*.jpg; do echo $filename; done 返回什么?
  • 我发现了问题。删除管道“|”之后的反斜杠“\”使其工作。我猜不应该在 bash 脚本中转义换行符。这是正确的吗?
  • 反斜杠不是必需的,但不会造成任何麻烦。后面可能有一个空格,或者类似的东西?

标签: regex bash sed mv


【解决方案1】:

你可以在 bash 中试试这个脚本:

for filename in *.jpg; do
  newFilename=$(sed -E 's#img_([0-9]{1,2})-([0-9]{1,2})-([0-9]{1,2})_(.*)$#newyears_20\3-\2-\1_\4#' <<< "$filename")
  mv "$filename" "$newFilename"
done

sed -E 也被gnu sed 支持。

【讨论】:

  • 你还想在 FreeBSD 上使用 -E。
  • 不错。如果值中有空格,可能会在 $filename 和 $newFilename 周围添加双引号。
【解决方案2】:

没有 for 循环。

ls | grep 'jpg$' | sed '
#Save the original filename
h
#Do the replacement
s/img_\(.*\)-\(.*\)-\(.*\)_\([0-9][0-9]\)\./newyears_20\3-\1-\2_0\4.//
s/img_\(.*\)-\(.*\)-\(.*\)_\([0-9][0-9][0-9]\)/newyears_20\3-\1-\2_\4//
#Bring the original filename back
x
G
s/^\(.*\)\n\(.*\)$/mv "\1" "\2"' | bash

省略管道到 bash 以查看 mv 之前的结果

感谢http://www.gnu.org/software/sed/manual/sed.html#Rename-files-to-lower-case

【讨论】:

  • 不解析ls输出
  • @GillesQuenot 你可以给个理由,这会很有帮助。
【解决方案3】:

我记得我在搞这种事情。我发现创建一个脚本来执行你想做的事情通常很有用:

即。您的脚本的输出将是一个文件,如:

mv   file1 file2
mv   file3 file4
.....
mv   fileN fileM

要创建它,只需执行 ls | grep 日期模式 | sed 脚本将 mv file1 粘贴到 file2 > myscript

然后执行 ./myscript

这样您可以更好地查看中间输出以找出问题所在。

【讨论】:

    【解决方案4】:

    这个简单的变体对我有用:

    $ cat mapper
    for filename in ?*.jpg
    do
        newFilename=$(echo $filename | \
        sed -e 's/img_\(.*\)-\(.*\)-\(.*\)_\([0-9][0-9]\)\./newyears_20\3-\1-\2_0\4./' \
            -e 's/img_\(.*\)-\(.*\)-\(.*\)_\([0-9][0-9][0-9]\)/newyears_20\3-\1-\2_\4/')
        echo mv $filename $newFilename
    done
    $ echo > img_04-23-09_123.jpg
    $ echo > img_08-13-08_33.jpg
    $ sh mapper
    mv img_04-23-09_123.jpg newyears_2009-04-23_123.jpg
    mv img_08-13-08_33.jpg newyears_2008-08-13_033.jpg
    $
    

    唯一的区别是使用显式 -e 选项代替分号。

    在 MacOS X 10.6.7 上测试。

    【讨论】:

    • 看起来太脆弱了。需要报价
    【解决方案5】:

    它可以由纯 bash 脚本处理。

    for j in ?*.jpg
    do
      n="newyears_20${j:10:2}-${j:4:2}-${j:7:2}";
      if [ ${j:15:1} = "." ];then
        n="${n}_0${j:13}"
      else
        n="${n}${j:12}"
      fi
      mv $j $n
    done
    

    【讨论】:

    • 看起来太脆弱了。需要报价
    【解决方案6】:

    Ruby(1.9+)

    $ ruby -e 'Dir["img*jpg"].each{|x|File.rename(x,x.gsub(/img_(.*?)-(.*?)-(.*?)\.jpg/,"newyears_20\\2-\\1-\\3.jpg") )}'
    

    【讨论】:

      【解决方案7】:
      for f in *.jpg; do
        n=$(sed -r 's/^(.+)-([^_]+)_(.+)\.jpg/\2-\1_\3.jpg/' <<< "${f#img_}")
        mv "$f" "newyears_20$n"
      done
      

      &lt;&lt;&lt; 是一个称为here stringbash 功能,${f#img_}$f 中删除了img_ 前缀。 sed 表达式将img_MM-DD-YY_XX.jpg 转换为YY-MM-DD_XX.jpg,方法是将MM-DD 隔离为\1,将YY 隔离为\2,并将XX 隔离为\3,然后形成\2-\1_\3.jpg。请注意,n 分配中不需要引用。

      为了安全起见,对于这样的事情,我实际上更喜欢使用echo mv 而不是mv,所以我可以看到它会生成的命令。然后您可以删除echo 或将输出通过管道传输到sh

      【讨论】:

      • 看起来太脆弱了。需要报价
      • 请为您的答案添加解释以获得长期价值,以便未来的访问者可以从您的解决方案中学习,并将这些知识应用于他们自己的编码问题。仅代码的答案不受欢迎,并且不太可能获得支持。
      • 修复了引用,添加了解释。实际上,重写了整个事情,因为输出都是错误的。我想我当时没有测试它。
      猜你喜欢
      • 2014-06-08
      • 2020-10-08
      • 2019-01-09
      • 2013-08-27
      • 2019-10-05
      • 1970-01-01
      • 2011-01-23
      • 2013-06-12
      • 1970-01-01
      相关资源
      最近更新 更多