
我有兩組文件:
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~')