
두 가지 파일 세트가 있습니다.
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 기능을 사용하지 않으며 파일 이름에 대한 최소한의 온전성 검사만 수행합니다.
메모:jq것보다 훨씬 더 많은 기능을 제공 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
같은 파일 이름 접미사를 추가하는 것을 의미합니다 . 또한 현재 수행 중인 작업 에 대한 일부 출력을 얻기 위해 여기에 GNU에 옵션을 추가했습니다 ..~1~
.~2~
-v
mv
mv
renamed 'file.txt' -> 'Untitled' (backup: 'Untitled.~2~')