두 가지 파일 세트가 있습니다.
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
이것은 다음을 사용하는 매우 간단하고 간단한 쉘 스크립트입니다.JSON 파이프라인당신이 원하는 것을하십시오. 멋진 sh/bash 기능을 사용하지 않으며 파일 이름에 대해 최소한의 온전성 검사만 수행합니다.
노트:잭json보다 훨씬 강력 jsonpipe
하지만 jsonpipe
json 데이터의 구조에 특별히 관심이 없거나 이해하고 싶지 않고 하나 또는 두 개의 필드를 추출하고/하거나 행을 사용하여 json을 사용하려는 경우 사용하기 더 간단하고 쉽습니다. 지향적인 텍스트 처리 도구(예: awk
등)는 데이터 처리를 수행합니다 sed
.grep
한 가지 확실한 개선 사항은 printf
0으로 채워진 정수 필드를 사용하여 파일 이름을 고정 너비의 번호가 매겨진 이름으로 바꾸는 것입니다. 예를 들어 Untitled-0001.txt
원하는 Untitled-1.txt
경우 이를 수행하도록 남겨 두겠습니다.
작성된 대로 실제로 파일 이름을 바꾸지는 않습니다. mv
명령 만 인쇄합니다.회의사용. 실제로 파일 이름을 바꾸도록 echo
각 명령 앞의 를 제거하도록 편집하십시오 .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
파일 이름 접미사 .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
파일 이름 접미사(예 .~1~
: , 등)를 추가하는 것을 의미합니다. 또한 수행 중인 작업에 대한 일부 출력을 얻기 위해 여기에 GNU 옵션을 .~2~
추가했습니다 .-v
mv
mv
renamed 'file.txt' -> 'Untitled' (backup: 'Untitled.~2~')