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.txt。したがって、新しいファイルの名前を に変更する必要がありますUntitled-1.txt。次に、 もUntitled-2.txt同様に になります。

答え1

これは、非常にシンプルでわかりやすいシェルスクリプトです。jsonパイプ必要なことを実行します。高度な sh/bash 機能は使用せず、ファイル名の最低限の妥当性チェックのみを実行します。

注記:jqは よりもはるかに優れていますjsonpipeが、 JSON データの構造を特に気にしない (または知りたい) 場合や、1 つまたは 2 つのフィールドのみを抽出したい場合、または、などjsonpipeの行指向のテキスト処理ツールで JSON データを使用したい場合には、 の方がシンプルで使いやすくなりますawksedgrep

printf明らかに可能な機能強化の 1 つは、ゼロ埋めされた整数フィールドを使用して、ファイル名Untitled-0001.txtを ではなく などの固定幅の番号付きの名前に変更することですUntitled-1.txt。必要な場合は、これを実行してください。

書かれているとおり、実際にはファイル名は変更されません。mvコマンドが出力されるだけです。だろう使用します。echomvコマンドの前の from を削除して、実際にファイル名を変更するように編集します。

#! /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置き換えることで、変数に対応する JSON ファイル名が割り当てられます。.txt.json

生成されたファイル名が既存のファイルに対応する場合、jqその JSON ファイルを解析するために使用されます。現在のファイルの名前をドキュメント内のキーの文字列値に変更するためのシェル コマンドを構築します.title。シェルは、ファイルの名前を変更する生成されたコマンドを評価します。

JSON ファイルの有効性はチェックされず、名前の競合は処理されません。

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

jq式を次のように修正します

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

GNU による番号付きバックアップとは、バックアップされたファイルの末尾に 、 などのファイル名サフィックスを追加することを意味します。また、GNUmvに、実行内容に関する出力を取得するオプションを追加しました。.~1~.~2~-vmvmv

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

関連情報