Benennen Sie Dateien basierend auf JSON-Inhalten um

Benennen Sie Dateien basierend auf JSON-Inhalten um

Ich habe zwei Dateisätze:

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

Die JSON-Dateien enthalten das folgende Format:

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

Ich möchte jedes fileX.txtmit dem Parameterwert titleaus der jeweiligen fileX.jsonDatei umbenennen.

Zum Beispiel,

rename fileX.txt -> Untitled

Ich kann diesen Wert wie folgt herausfiltern;

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

Wenn ich jedoch auf einen vorhandenen Dateinamen stoße, sollte dieser sich mit einem Suffix umbenennen.

Nehmen wir beispielsweise an, es gibt bereits eine Untitled.txt. Die neue Datei sollte also in umbenannt werden Untitled-1.txt. Die nächste Begegnung erfolgt Untitled-2.txtebenfalls in .

Antwort1

Hier ist ein ziemlich einfaches und unkompliziertes Shell-Skript, dasjsonpipeum zu tun, was Sie wollen. Es verwendet keine ausgefallenen sh/bash-Funktionen und führt nur die absolut notwendige Plausibilitätsprüfung der Dateinamen durch.

NOTIZ:jqist weitaus leistungsfähiger als jsonpipe, aber jsonpipeeinfacher und leichter zu verwenden, wenn Sie sich nicht besonders für die Struktur der JSON-Daten interessieren (oder diese nicht kennen möchten) und nur ein oder zwei Felder extrahieren und/oder JSON-Daten mit zeilenorientierten Textverarbeitungstools wie awk, sed, grepusw. verwenden möchten.

Eine offensichtliche mögliche Verbesserung ist die Verwendung printfeines mit Nullen aufgefüllten Integer-Felds, um Dateien in nummerierte Namen mit fester Breite umzubenennen, z. B. Untitled-0001.txtstatt Untitled-1.txt. Ich überlasse das Ihnen, wenn Sie es möchten.

So wie es geschrieben ist, wird es keine Datei umbenennen. Es wird nur der mvBefehl ausgegeben, den eswürdeverwenden. Bearbeiten Sie es, um das echo„von“ vor jedem mvBefehl zu entfernen, damit die Dateien tatsächlich umbenannt werden.

#! /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

Anwendungsbeispiele / Nachweis der Wirksamkeit:

$ 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

Antwort2

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

Dies durchläuft alle Namen im aktuellen Verzeichnis, die dem Muster entsprechen file*.txt. Für jeden dieser Namen jsonwird der Variablen der entsprechende JSON-Dateiname zugewiesen, indem das .txtDateinamensuffix durch ersetzt wird .json.

Wenn der generierte Dateiname einer vorhandenen Datei entspricht, jqwird zum Parsen dieser JSON-Datei verwendet. Es erstellt einen Shell-Befehl zum Umbenennen der aktuellen Datei in den Zeichenfolgenwert des .titleSchlüssels im Dokument. Die Shell wertet den generierten Befehl aus, der die Datei umbenennt.

Es erfolgt keine Prüfung auf die Gültigkeit der JSON-Datei und Namenskollisionen werden nicht behandelt.

Der einfachste Weg, mit Namenskollisionen umzugehen, besteht darin, sicherzustellen, dass Sie mvGNU Coreutils verwenden, und dann dessen --backupOption zu nutzen.

Ändern Sie den jqAusdruck in

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

Nummerierte Backups mit GNU mvbedeuten, dass Dateinamensuffixe wie .~1~, .~2~, usw. an das Ende der gesicherten Dateien angehängt werden. Ich habe -vGNU hier auch die Option hinzugefügt, eine Ausgabe über das Geschehen mvzu erhalten , wiemv

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

verwandte Informationen