我有两组文件:
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
这是一个相当简单直接的 shell 脚本,它使用json管道做你想做的事。它不使用任何花哨的 sh/bash 功能,并且仅对文件名进行最低限度的健全性检查。
笔记:杰克比 json 功能强大得多jsonpipe
,但当jsonpipe
您不特别关心(或想了解)json 数据的结构并且只想提取一两个字段和/或想要使用 json 时,它更简单且更易于使用使用面向行的文本处理工具(例如awk
,等)进行数据处理sed
。grep
一个明显的可能增强功能是使用printf
零填充整数字段将文件重命名为固定宽度编号名称,例如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 文件。它构建一个 shell 命令,用于将当前文件重命名为.title
文档中键的字符串值。 shell 评估生成的重命名文件的命令。
不检查 JSON 文件的有效性,也不处理名称冲突。
处理名称冲突的最简单方法是确保您使用的mv
是 GNU coreutils,然后使用其--backup
选项。
将表达式修改jq
为
jq -r --arg name "$name" '[ "mv", "-v", "--backup=numbered", "--", $name, .title ] | @sh' "$json"
使用 GNU 进行编号备份mv
意味着将文件名后缀(如.~1~
、.~2~
等)添加到备份文件的末尾。我还在此处添加了-v
GNU 选项mv
,以获取有关mv
正在执行的操作的一些输出,例如
renamed 'file.txt' -> 'Untitled' (backup: 'Untitled.~2~')