根据 JSON 内容重命名文件

根据 JSON 内容重命名文件

我有两组文件:

file1.txt     file1.json 
file2.txt     file2.json    
file3.txt     file3.json  
...
fileN.txt     fileN.json

JSON 文件包含以下格式:

{ "ago": "59 sec ago",  "base_time": 1401243133,  "title": "Untitled",  "type": "None",  "retrieval_time": 1401624105,  "id": "qwNAgvYZ" }

我想用相应文件中的参数fileX.txt值重命名每个文件。titlefileX.json

例如,

rename fileX.txt -> Untitled

我可以按如下方式过滤掉该值;

cat fileX.json | awk -F"\"" '{print $10}'

但如果我遇到现有的文件名,它应该用后缀重命名。

例如,假设有一个现有的Untitled.txt.因此新文件应重命名为Untitled-1.txt.下次相遇也同样Untitled-2.txt如此。

答案1

这是一个相当简单直接的 shell 脚本,它使用json管道做你想做的事。它不使用任何花哨的 sh/bash 功能,并且仅对文件名进行最低限度的健全性检查。

笔记:杰克比 json 功能强大得多jsonpipe,但当jsonpipe您不特别关心(或想了解)json 数据的结构并且只想提取一两个字段和/或想要使用 json 时,它更简单且更易于使用使用面向行的文本处理工具(例如awk,等)进行数据处理sedgrep

一个明显的可能增强功能是使用printf零填充整数字段将文件重命名为固定宽度编号名称,例如Untitled-0001.txt而不是Untitled-1.txt.如果你愿意的话,我会把这件事留给你去做。

正如所写,它实际上不会重命名任何文件。它只会打印mv它的命令使用。编辑它以删除echo每个命令之前的mv,使其真正重命名文件。

#! /bin/sh

for f in file*.txt ; do
  b=$(basename "$f" .txt)

  # ignore current .txt file if there's no matching .json file
  if [ -e "$b.json" ] ; then
    # extract the title field.
    title=$(jsonpipe < "$b.json" | 
            awk -F'\t' '$1=="/title" {gsub(/\"/,"",$2) ; print $2}')

    if [ -n "$title" ] ; then
      if [ ! -e "$title.txt" ] ; then
        echo mv -v "$f" "$title.txt"
      else
        # are there any other "$title-*.txt" filenames?
        others=$(find . -maxdepth 1 -name "$title-*.txt")
        if [ -z "$others" ] ; then
          echo mv -v "$f" "$title-1.txt"
        else
          # use version-sort to get highest $title- number used.
          highest=$(printf "%s\n" "$others" | sort -V | tail -n 1)
          hnum=$(printf "%s\n" "$highest" | sed -e 's/^.*-// ; s/\.txt$//')
          hnum=$(( highest_num + 1))
          echo mv -v "$f" "$title-$hnum.txt"
        fi
      fi
    fi
  fi
done

使用示例/其有效的证明:

$ ls -l
total 8
-rw-rw-r-- 1 cas cas 132 May 19 23:47 file1.json
-rw-rw-r-- 1 cas cas   0 May 20 00:04 file1.txt
-rwxrwxr-x 1 cas cas 797 May 20 00:04 json-rename.sh

$ cat file1.json 
{"ago": "59 sec ago", "base_time": 1401243133, "title": "Untitled",
 "type": "None", "retrieval_time": 1401624105, "id": "qwNAgvYZ"}

$ ./json-rename.sh 
mv -v file1.txt Untitled.txt

$ touch Untitled.txt
$ ./json-rename.sh 
mv -v file1.txt Untitled-1.txt

$ touch Untitled-1.txt
$ ./json-rename.sh 
mv -v file1.txt Untitled-2.txt

$ touch Untitled-999.txt
$ ./json-rename.sh 
mv -v file1.txt Untitled-1000.txt

答案2

for name in file*.txt; do
    json=${name%.txt}.json
    if [ -f "$json" ]; then
        eval "$(
            jq -r --arg name "$name" '[ "mv", "--", $name, .title ] | @sh' "$json"
        )"
    fi
done

这将循环当前目录中与模式匹配的所有名称file*.txt。对于每个此类名称,json通过将文件名后缀替换.txt.json.

如果生成的文件名对应于现有文件,jq则用于解析该 JSON 文件。它构建一个 shell 命令,用于将当前文件重命名为.title文档中键的字符串值。 shell 评估生成的重命名文件的命令。

不检查 JSON 文件的有效性,也不处理名称冲突。

处理名称冲突的最简单方法是确保您使用的mv是 GNU coreutils,然后使用其--backup选项。

将表达式修改jq

jq -r --arg name "$name" '[ "mv", "-v", "--backup=numbered", "--", $name, .title ] | @sh' "$json"

使用 GNU 进行编号备份mv意味着将文件名后缀(如.~1~.~2~等)添加到备份文件的末尾。我还在此处添加了-vGNU 选项mv,以获取有关mv正在执行的操作的一些输出,例如

renamed 'file.txt' -> 'Untitled' (backup: 'Untitled.~2~')

相关内容