JSONコンテンツに基づいてファイル名を変更する

JSONコンテンツに基づいてファイル名を変更する

2つのファイルセットがあります。

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.txtUntitled-1.txtUntitled-2.txt

答え1

これは、以下を使用する非常にシンプルでシンプルなシェルスクリプトです。JSONパイプラインあなたが欲しいものをしてください。素晴らしいsh / bash機能を使用せず、ファイル名に対して最小限の完全性チェックのみを実行します。

メモ:ジャックjsonよりはるかに強力jsonpipeですが、jsonpipejsonデータの構造に特に興味がない、または理解したくないので、1つまたは2つのフィールドを抽出したり、または行を使用してjsonを使用したい場合は、使用する方が簡単で簡単です。指向のテキスト処理ツール(例:awkなど)はデータ処理を実行しますsedgrep

1つの明確な改善点は、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

生成されたファイル名が既存のファイルと一致する場合は、jqJSONファイルを解析するために使用されます。現在のファイルの名前を.title文書内のキーの文字列値に置き換えるシェルコマンドを作成します。シェルは生成されたコマンドを評価してファイルの名前を変更します。

JSONファイルは検証されず、名前の競合は処理されません。

名前の競合を処理する最も簡単な方法は、GNU coreutilsを使用していることを確認してから、そのmvオプション--backupを使用することです。

式をjq次に変更します。

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

GNUを使用して番号付きバックアップを作成することは、バックアップファイルの末尾にmvファイル名のサフィックス(たとえば、.~1~など)を追加することを意味します。また、実行中の操作のいくつかの出力を取得するためにここにGNUオプションを.~2~追加しました。-vmvmv

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

関連情報