
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.txt
mit dem Parameterwert title
aus der jeweiligen fileX.json
Datei 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.txt
ebenfalls 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 jsonpipe
einfacher 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
, grep
usw. verwenden möchten.
Eine offensichtliche mögliche Verbesserung ist die Verwendung printf
eines mit Nullen aufgefüllten Integer-Felds, um Dateien in nummerierte Namen mit fester Breite umzubenennen, z. B. Untitled-0001.txt
statt 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 mv
Befehl ausgegeben, den eswürdeverwenden. Bearbeiten Sie es, um das echo
„von“ vor jedem mv
Befehl 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 json
wird der Variablen der entsprechende JSON-Dateiname zugewiesen, indem das .txt
Dateinamensuffix durch ersetzt wird .json
.
Wenn der generierte Dateiname einer vorhandenen Datei entspricht, jq
wird zum Parsen dieser JSON-Datei verwendet. Es erstellt einen Shell-Befehl zum Umbenennen der aktuellen Datei in den Zeichenfolgenwert des .title
Schlü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 mv
GNU Coreutils verwenden, und dann dessen --backup
Option zu nutzen.
Ändern Sie den jq
Ausdruck in
jq -r --arg name "$name" '[ "mv", "-v", "--backup=numbered", "--", $name, .title ] | @sh' "$json"
Nummerierte Backups mit GNU mv
bedeuten, dass Dateinamensuffixe wie .~1~
, .~2~
, usw. an das Ende der gesicherten Dateien angehängt werden. Ich habe -v
GNU hier auch die Option hinzugefügt, eine Ausgabe über das Geschehen mv
zu erhalten , wiemv
renamed 'file.txt' -> 'Untitled' (backup: 'Untitled.~2~')