Shell-Script

根據文件名將文件排序到多個目錄中?

  • October 31, 2019

我在一個目錄中有 1000 個文件,我想根據它們的文件名將它們分類到子目錄中。它們都一致地以一組 p- 結構命名

$$ number $$_n-$$ number $$_一種-$$ number $$.$$ ext $$. 這是一個小樣本…

  • p-12345_n-987_a-1254.jpg
  • p-12345_n-987_a-9856.pdf
  • p-12345_n-987_a-926.docx
  • p-12345_n-384_a-583.pdf
  • p-12345_n-384_a-987.pdf
  • p-2089_n-2983_a-2348.gif
  • p-2089_n-1982_a-403.jpeg
  • p-38422_n-2311_a-126.pdf
  • p-38422_n-2311_a-5231.docx

我所追求的是這樣的文件夾結構:

p-12345
 ⊢ n-987
   ⊢ p-12345_n-987_a-1254.jpg
   ⊢ p-12345_n-987_a-9856.pdf
   ⊢ p-12345_n-987_a-926.docx
 ⊢ n-384
   ⊢ p-12345_n-384_a-583.pdf
   ⊢ p-12345_n-384_a-987.pdf
p-2089
 ⊢ n-2983
   ⊢ p-2089_n-2983_a-2348.gif
 ⊢ n-1982
   ⊢ p-2089_n-1982_a-403.jpeg
p-38422
 ⊢ n-2311
   ⊢ p-38422_n-2311_a-126.pdf
   ⊢ p-38422_n-2311_a-5231.docx

我希望這是有道理的。

是否可以編寫腳本以這種方式組織文件?

編輯:澄清:是的,我的問題應該是如何編寫腳本來組織文件?:) 我對 Unix 和一般的命令行都很陌生。到目前為止,我只編寫/使用了基本的 shell 腳本。我有一種預感,答案可能涉及正則表達式,但除此之外,我不確定從哪裡開始。

我想出的最好的主意是

  1. 將文件列表導出到文本文件
  2. 查找並用“/n”和“/a”替換“_n”和“_a”
  3. 從中創建一系列 mv 命令
  4. 將其保存為 shell 腳本

我敢肯定,這比它需要的要冗長得多。我還想有一些可重複的東西,以防我將來需要為更多文件做這件事。

如前所述,簡短的回答是“是”。

長答案是:您可以使用 bash 腳本來執行此操作,該腳本用於awk提取您想要作為目錄結構基礎的文件名元素。它可能看起來像這樣(更強調可讀性而不是“單行”緊湊性)。

#!/bin/bash


for FILE in p-*
do
   if [[ ! -f $FILE ]]; then continue; fi

   LVL1="$(awk '{match($1,"^p-([[:digit:]]+)_[[:print:]]*",fields); print fields[1]}' <<< $FILE)"
   LVL2="$(awk '{match($1,"^p-([[:digit:]]+)_n-([[:digit:]]+)_[[:print:]]*",fields); print fields[2]}' <<< $FILE)"

   echo "move $FILE to p-$LVL1/n-$LVL2"
   if [[ ! -d "p-$LVL1" ]]
   then
   mkdir "p-$LVL1"
   fi

   if [[ ! -d "p-$LVL1/n-$LVL2" ]]
   then
   mkdir "p-$LVL1/n-$LVL2"
   fi

   mv $FILE "p-$LVL1/n-$LVL2"
done

解釋:

  • 我們對目前目錄中以“p-”開頭的所有文件執行循環。
  • 循環中的第一條指令確保文件存在並且是空目錄的解決方法(之所以需要這樣做是因為在這個論壇上,您總是被告知不要解析 的輸出ls,所以類似的東西FILES=$(ls p-*); for FILE in $FILES; do ...會被認為是不行)。
  • 然後,我們提取p-_n生成目錄結構的第一級所需的數字awk(正如您所懷疑的,使用正則表達式),對於第二級之間的數字n-也是_a如此。這個想法是使用該函式不僅查找指定正則表達式在您的輸入中出現的位置,而且還為您提供數組“欄位”match中圓括號中所有元素的“完成”值。( ... )
  • 第三,我們檢查您的預期目錄結構的第一級和第二級目錄是否已經存在。如果沒有,我們創建它們。
  • 最後,我們將文件移動到目標目錄。

有關更多資訊,請查看高級 bash 腳本指南GNU Awk 使用者指南

一旦您在腳本和正則表達式方面更加堅定,您就可以使其更加緊湊;例如,在上面的腳本中,目錄/子目錄路徑的生成可以很容易地簡化為一次awk呼叫。

  • 一方面,由於目錄名稱實際上是 p-<number>and n-<number>,與您的文件名中的相同,因此我們也可以讓我們awk為我們提取這些字元,方法是編寫 match($1,"(^p-[[:digit:]]+)_(n-[[:digit:]]+)_[[:print:]]*",fields)
  • 我們可以awk通過使用合適的參數同時生成目錄子目錄路徑來進一步解除安裝工作print
awk '{match($1,"(^p-[[:digit:]]+)_(n-[[:digit:]]+)_[[:print:]]*",fields); print fields[1] "/" fields[2]}'

很容易p-12345/n-384為 file產生(例如) p-12345_n-384_a-583.pdf。如果我們將其與mkdir -p@wurtel 所示的用法結合起來,腳本可能看起來像

for FILE in p-*
do
   if [[ ! -f $FILE ]]; then continue; fi

   TARGET="$(awk '{match($1,"(^p-[[:digit:]]+)_(n-[[:digit:]]+)_[[:print:]]*",fields); print fields[1] "/" fields[2]}' <<< $FILE)"
   echo "move $FILE to $TARGET"

   mkdir -p "$TARGET"
   mv $FILE $TARGET
done

當然:

#!/bin/bash
for i in p-*_n-*.*; do
       Ppart=${i/_n-*}
       x=${i/${Ppart}_/}
       nPart=${x/_a-*}
       mkdir -p $Ppart/$nPart
       mv $i $Ppart/$nPart
done

首先遍歷與您提供的模式匹配的所有文件名。在每個循環中,使用 shell 替換從部分開始刪除文件名的最後一部分_n-,這給出了 P 部分(第一級目錄)。現在我們需要 N 部分,從n-up 到_a-部分。我分兩步執行此操作:首先刪除 Ppart,然後從該部分開始的最後_a-一部分。

現在用於mkdir -p創建必要的目錄。mkdir -p如果路徑已經存在,則不會給出錯誤,因此mkdir -p在決定執行命令之前執行而不是測試目錄是否存在更容易。

最後將文件 mv 到正確的目錄中。

引用自:https://unix.stackexchange.com/questions/549259