使用排序按字母顺序排列文件名中的单词?

使用排序按字母顺序排列文件名中的单词?

当阅读有关在 bash 中批量重命名文件并使用命令sort对文件内容进行排序的教程时,我无法弄清楚如何将两者结合起来。

我有一个目录,其内容使用文件名中的标签进行排序,类似于程序的方式标签空间处理事情。当我创建或下载文件时,我会在文件名末尾添加我能想到的任何标签。这是一个例子:

Sunrise (2) #wallpaper #4k #googleimages.jpg

现在我想浏览所有这些文件并重命名它们,以便标签按字母顺序排序,而不影响标签之前或之后的任何内容(例如图片的标题或文件扩展名)。所以上面的内容就变成了:

Sunrise (2) #4k #googleimages #wallpaper.jpg

我该如何实现这个目标?我什至不知道如何传递文件姓名,而不是它的内容,到像这样的命令sort,然后我可以将其输出传输到mv.

答案1

#!/bin/bash

for i in dir_for_files/*; do
    filename=${i%%#*}
    sorted_tags=$(grep -o "#[^ .]*" <<< "$i" | sort -n | tr '\n' ' ')
    ext=${i#*.}
    echo mv "$i" "${filename}${sorted_tags% }.$ext"
done

测试:

##### Before sorting #####    
$ ls -1 dir_for_files
Note (3) #textfile #notes #important.txt
Sunrise (2) #wallpaper #4k #googleimages.jpg
Sunset (2) #wallpaper #2k #images.jpg

$ ./sort_tags.sh

##### After sorting #####
$ ls -1 dir_for_files
Note (3) #important #notes #textfile.txt
Sunrise (2) #4k #googleimages #wallpaper.jpg
Sunset (2) #2k #images #wallpaper.jpg

答案2

如果您有基于 perl 的renameprename在某些系统上),那么您可以使用 perl 对标签进行拆分+排序。例如,给定

$ ls *.jpg
Sunrise (2) #wallpaper #4k #googleimages.jpg

然后(通过一些丑陋的争论来删除和替换后缀.jpg

$ rename -v 'my @F = split / #/, substr($_,0,-4); $_ = (join " #", shift @F, sort @F) . ".jpg"' *.jpg
Sunrise (2) #wallpaper #4k #googleimages.jpg renamed as Sunrise (2) #4k #googleimages #wallpaper.jpg

检查

$ ls *.jpg
Sunrise (2) #4k #googleimages #wallpaper.jpg

可能还有很多改进的空间 - 但我希望它能给你一些想法。

答案3

zsh

autoload zmv # best in ~/.zshrc
zmv -n '([^#]#)(\#*)(.*)' '$1${(j: :)${(os: :)2}}$3'

-n如果满意,请删除(空运行))。

  • [^#]#: 0 个或多个非 # 字符(#类似于*正则表达式)
  • s: :在空间上分裂
  • o: 顺序(排序)
  • j: ::与空间连接。

#因此,我们在空间上分割第一个(包含)和最后一个(排除)之间的部分.,对结果列表进行排序,然后使用空间将其重新合并。

递归地:

zmv -n '(**/)([^#]#)(\#*)(.*)' '$1$2${(j: :)${(os: :)3}}$4'

为了允许标签名称中存在空格,我们可以拆分#并修剪尾随空格,排序并连接#

zmv -n '([^#]#\#)(*)(.*)' '$1${(j: #:)${(os:#:)2}%% #}$3'

(#qD)如果您还想处理隐藏文件(Dot 文件)或想要处理隐藏目录中的文件,请添加glob 限定符。

答案4

老实说,这对于 Bash 来说似乎有点太复杂了。这并非不可能,但在我看来,最好使用专为“真正”编程而设计的语言。 Bash 解决方案可能无法维护。 (并不是想侮辱仅 Bash 的解决方案,我认为重命名魔法实际上非常神奇)

也就是说,这是 Ruby 的解决方案。如果您安装了 Ruby,您可以将其写入文件,然后从 shell 中执行该文件。

#!/usr/bin/env ruby
Dir.glob('*.jpg').each do |filename|
    # `name` contains the name of the file, without the tags. `tags` is an array
    # of all tags of the file.
    name, *tags = filename.split(' #')
    # if there aren't any tags, just skip the file.
    if tags.empty?
        next
    end
    # remove the trailing '.jpg' and sort all the tags
    tags.last.gsub!(/\.jpg$/,'')
    tags.sort!
    tags = [name] + tags
    # finally, move the file to the correct location with sorted tags.
    File.rename filename, "#{tags.join(' #')}.jpg"
end

要执行该脚本,只需将其放在图像所在的目录中即可。此解决方案应该对愚蠢的图像名称和标签具有相当的弹性,C#不会导致问题。也就是说,请务必在运行脚本之前进行备份。移动操作可能与rm.

相关内容