根據 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~')

相關內容