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값으로 각각의 이름을 바꾸고 싶습니다 .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하지만 jsonpipejson 데이터의 구조에 특별히 관심이 없거나 알고 싶지 않고 하나 또는 두 개의 필드만 추출하려는 경우 및/또는 json을 사용하려는 경우 사용하기가 더 간단하고 쉽습니다. , 등과 같은 줄 중심 텍스트 처리 도구를 사용하여 데이터를 생성합니다 awk.sedgrep

한 가지 확실한 개선 사항은 printf0으로 채워진 정수 필드를 사용하여 파일 이름을 고정 너비 번호가 붙은 이름(예 Untitled-0001.txt: Untitled-1.txt. 원하신다면 그렇게 하도록 남겨두겠습니다.

작성된 대로 실제로 파일 이름은 바뀌지 않습니다. mv해당 명령 만 인쇄합니다 .~일 것이다사용. echomv명령 앞의 를 제거하여 실제로 파일 이름을 바꾸도록 편집하세요 .

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

생성된 파일 이름이 기존 파일에 해당하는 경우 jq해당 JSON 파일을 구문 분석하는 데 사용됩니다. 현재 파일의 이름을 .title문서에 있는 키 의 문자열 값으로 바꾸는 쉘 명령을 작성합니다 . 쉘은 파일 이름을 바꾸는 생성된 명령을 평가합니다.

JSON 파일의 유효성은 확인되지 않으며 이름 충돌은 처리되지 않습니다.

이름 충돌을 처리하는 가장 쉬운 방법은 GNU coreutils에서 사용하고 있는지 확인한 mv다음 해당 --backup옵션을 사용하는 것입니다.

jq표현식을 다음으로 수정하세요 .

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

GNU를 사용한 번호 매기기 백업은 백업된 파일 끝에 , 등과 mv같은 파일 이름 접미사를 추가하는 것을 의미합니다 . 또한 현재 수행 중인 작업 에 대한 일부 출력을 얻기 위해 여기에 GNU에 옵션을 추가했습니다 ..~1~.~2~-vmvmv

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

관련 정보