假設我在這樣的檔案夾中:
? tmp.lDrLPUOF ls
1.txt 2.txt 3.txt 1.zip 2.rb
我想將文本檔案的所有檔案名放入特定的 JSON 格式,如下所示:
{
"": [
{
"title": "",
"file": "1"
},
{
"title": "",
"file": "2"
},
{
"title": "",
"file": "3"
}
]
}
現在我只知道如何列出所有檔案名:
? tmp.lDrLPUOF ls *'.txt'
1.txt 2.txt 3.txt
我可以使用 bash 或 Perl 來達到這個目的嗎?非常感謝!
編輯
感謝@Charles Duffy 和@Shawn 的精彩回答。但是忘記了另一個重要的資訊——時間是我的錯。我想根據創建時間將檔案名放入生成的 JSON 中。
創建時間如下:
? tmp.lDrLPUOF ls -lTr
total 0
-rw-r--r-- 1 administrator staff 0 Oct 12 09:35:05 2022 3.txt
-rw-r--r-- 1 administrator staff 0 Oct 12 09:35:08 2022 2.txt
-rw-r--r-- 1 administrator staff 0 Oct 12 09:35:12 2022 1.txt
所以我想要的結果 JSON 應該是這樣的:
{
"": [
{
"title": "",
"file": "3"
},
{
"title": "",
"file": "2"
},
{
"title": "",
"file": "1"
}
]
}
uj5u.com熱心網友回復:
{ shopt -s nullglob; set -- *.txt; printf '%s\0' "$@"; } | jq -Rn '
{"": [ input
| split("\u0000")[]
| select(. != "")
| {"title": "",
"file": . | rtrimstr(".txt")
}
]
}
'
讓我們把它分解成碎片。
在 bash 方面:
shopt -s nullglob告訴外殼如果*.txt沒有引數,它應該什么*.txt都不發出,而不是作為結果發出字串。set --覆寫當前背景關系中的引數串列(因為這是管道左側的塊,背景關系是瞬態的,不會"$@"在管道外的代碼中更改)。printf '%s\0' "$@"列印我們的引數,每個引數后面都有一個 NUL 字符;如果根本沒有引數,它只列印一個 NUL。
在 jq 方面:
-R指定輸入是原始資料,而不是 json。-n指定我們不會自動使用任何輸入,而是使用inputorinputs指定應該讀取輸入的位置。split("\u0000")在 NUL 上拆分輸入。(這很重要,因為 NUL 是檔案名中唯一不能存在的字符,這就是我們printf '%s\0'在 shell 端使用的原因;這樣我們就可以正確處理帶有換行符、文字引號、空格和所有其他怪異的檔案名那是能夠存在的)。select(. != "")忽略空字串。rtrimstr(".txt").txt從名稱中洗掉。
附錄:按 mtime 排序
jq 部分不需要在這里修改:要按 mtime 排序,您只能調整外殼。在具有 GNU和的系統上find,這可能如下所示:sortsed
find . -maxdepth 1 -type f -name '*.txt' -printf '%T@ %P\0' |
sort -zn |
sed -z -re 's/^[[:digit:].] //g' |
jq -Rn '
...后跟上面給出的相同 jq 。
uj5u.com熱心網友回復:
如果已安裝,tree則可以作為列出目錄內容的一個很好的替代方案,因為它可以將其輸出編碼為定義明確的 JSON,這在處理奇怪的檔案名時會派上用場(尤其是當您想要的輸出是 JSON 時)。
tree -JtL 1 -P '*.txt'
[
{"type":"directory","name":".","contents":[
{"type":"file","name":"3.txt"},
{"type":"file","name":"2.txt"},
{"type":"file","name":"1.txt"}
]}
,
{"type":"report","directories":0,"files":3}
]
tree -J輸出 JSONtree -t按上次修改時間排序tree -L 1僅遞回1深度tree -P '*.txt'減少串列到檔案模式*.txt
當然,如果需要,您還可以添加更多詳細資訊,例如
tree -p包括檔案權限tree -u并tree -g包括用戶名和組名tree -s包括檔案大小(以位元組為單位)tree -D --timefmt '%F %T'包括最后修改時間
tree -JtL 1 -P '*.txt' -pusD --timefmt='%F %T'
[
{"type":"directory","name":".","mode":"0755","prot":"drwxr-xr-x","user":"hustnzj","size":4096,"time":"2022-10-12 09:35:00","contents":[
{"type":"file","name":"3.txt","mode":"0644","prot":"-rw-r--r--","user":"hustnzj","size":123,"time":"2022-10-12 09:35:05"},
{"type":"file","name":"2.txt","mode":"0644","prot":"-rw-r--r--","user":"hustnzj","size":456,"time":"2022-10-12 09:35:08"},
{"type":"file","name":"1.txt","mode":"0644","prot":"-rw-r--r--","user":"hustnzj","size":789,"time":"2022-10-12 09:35:12"}
]}
,
{"type":"report","directories":0,"files":3}
]
關于此評論的注釋:
tree -t按上次修改時間排序。還有一個選項tree -c來排序(并tree -D顯示時間)最后狀態更改,但沒有使用創建/出生時間(如果檔案系統支持)的專用選項(我知道)。
然后,使用該 JSON 輸出作為輸入,您可以使用jq進一步過濾和格式化:
tree … | jq --arg ext '.txt' '
{"": (first.contents | map(
select(.type == "file") | {title: "", file: .name | rtrimstr($ext)}
))}
'
{
"": [
{
"title": "",
"file": "3"
},
{
"title": "",
"file": "2"
},
{
"title": "",
"file": "1"
}
]
}
演示
注意:這包括過濾器select(.type == "file"),tree也包括子目錄的名稱。如果您希望它們包括在內,請將其洗掉。
uj5u.com熱心網友回復:
使用 just jq,任何外殼:
$ jq -n --args '{"": [ $ARGS.positional[] | rtrimstr(".txt") | { title: "", file: . } ] }' *.txt
{
"": [
{
"title": "",
"file": "1"
},
{
"title": "",
"file": "2"
},
{
"title": "",
"file": "3"
}
]
}
在命令列上傳遞的檔案名(擴展名*.txt在 jq 變數$ARGS.positional中。對于每個檔案名,洗掉 .txt 擴展名并在所需結構的物件中使用其余檔案名。
或者使用 perl 單行:
$ perl -MJSON::PP -E 'say encode_json({"" => [ map { { title => "", file => s/\.txt$//r } } @ARGV ] })' *.txt
{"":[{"file":"1","title":""},{"title":"","file":"2"},{"file":"3","title":""}]}
uj5u.com熱心網友回復:
我的看法:
stat -c '%Y:%n' *.txt \
| sort -t: -n \
| cut -d: -f2- \
| xargs basename -s .txt \
| jq -s 'map({title: "", file: tostring}) | {"": .}'
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/517845.html
標籤:Unixjq
上一篇:如何讓make只編譯?
