Переименовывать файлы на основе содержимого 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используя значение titleпараметра из соответствующего fileX.jsonфайла.

Например,

rename fileX.txt -> Untitled

Я могу отфильтровать это значение следующим образом:

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

Но если я встречаю существующее имя файла, он должен переименоваться, добавив суффикс.

Например, предположим, что существует Untitled.txt. Поэтому новый файл следует переименовать в Untitled-1.txt. Далее встречаем аналогично Untitled-2.txt.

решение1

Вот довольно простой и понятный скрипт оболочки, который используетjsonpipeделать то, что вы хотите. Он не использует никаких модных функций sh/bash и делает только минимальную проверку правильности имен файлов.

ПРИМЕЧАНИЕ:jqгораздо более функционален, чем jsonpipe, но jsonpipeпроще и удобнее в использовании, когда вас не особенно интересует (или вы не хотите знать) структура данных JSON и вы хотите извлечь только одно или два поля и/или хотите использовать данные JSON с инструментами обработки текста, ориентированными на построчную обработку, такими как , awkи т. д.sedgrep

Одним из очевидных возможных улучшений является использование printfс целочисленным полем, дополненным нулями, для переименования файлов в пронумерованные имена фиксированной ширины, например, Untitled-0001.txtвместо Untitled-1.txt. Я оставлю это вам, если вы этого хотите.

Как написано, он на самом деле не переименует ни один файл. Он только выведет команду, mvкоторую онбыиспользование. Отредактируйте его, удалив echofrom перед каждой 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присваивается соответствующее имя файла JSON путем замены .txtсуффикса имени файла на .json.

Если сгенерированное имя файла соответствует существующему файлу, jqиспользуется для разбора этого файла JSON. Он создает команду оболочки для переименования текущего файла в строковое значение ключа .titleв документе. Оболочка оценивает сгенерированную команду, которая переименовывает файл.

Проверка корректности файла JSON не производится, и конфликты имен не обрабатываются.

Самый простой способ справиться с конфликтами имен — убедиться, что вы используете mvGNU 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~')

Связанный контент