Shell

使用 FIND 和 MV 來重命名文件。刪除找到的字元串,然後將其添加到文件名中?

  • June 28, 2020
find . -type f -name '*authors-name-string*' -exec bash -c 'mv "$0" "${0/authors-name-string/}"' {} \;

我正在嘗試重命名嵌套在幾層目錄中的文件,這些目錄包含在文件名中隨機嵌入的作者姓名文本字元串。創建一個以作者姓名開頭的新文件名,後跟原始文件名的其餘部分……但沒有作者姓名字元串,該字元串位於原始文件名中的某個隨機位置。

上面的 shell 命令行將遞歸地從文件名中刪除 authors-name-text 字元串,但我還沒有弄清楚如何做到這一點並將作者姓名文本(和尾隨的“_”下劃線)添加到開標頭檔名。基本上我想將作者姓名文本從文件名中目前的任何位置移動到文件名的開頭(加上下劃線)。據我所知,在我的 Synology NAS 上呼叫的 bash 版本是 v4.3。我已經通過 ssh 從我的 MacBook 登錄。

試圖在按主題目錄名稱組織的不同目錄中獲取數千個文件,以便在查看簡單目錄列表時,目錄中同一作者編寫的一些文件出現在一組中。

find . -type f -name '*authors-name-string*' -exec bash -c 'mv "$0" "authors-name-string_${0/authors-name-string/}"' {} \;

上面的命令行在嘗試在整個文件名路徑的前面插入“authors-name-string_”時失敗。但是,由於沒有該名稱的起始目錄,因此 MV 命令會抱怨,它仍然會根據需要從文件名中的原始位置刪除作者名稱字元串。

擴展您的方法並利用參數擴展:

export author_string='author1'
export new_string='author1'
find . -type f -name "*${author_string}*" \
 -exec sh -c '
   path="${1%/*}"
   tmp="${1%%${author_string}[^/]*}"
   before="${tmp##*/}"
   after="${1##*${author_string}}"
   echo mv -- "$1" "${path}/${new_string}_${before}${after}"' sh {} \;

我的假設,因為我不確定我是否完全理解你的問題:

您正在搜尋名稱包含固定字元串的文件;在這裡,變數author_string.

您正在重命名目錄樹中的所有文件。

您的文件的新名稱將以固定字元串開頭(是否相同author_string,沒有太大區別);在這裡,變數new_string.

文件的新名稱的其餘部分將與其舊名稱相同,但author_string要刪除的部分除外。

在這段程式碼中:

  • 我們導出舊/新字元串以使它們可用於由find.

  • 著眼於便攜性,-exec呼叫sh. $1用於代替$0, 就像在您的程式碼片段中一樣,因為$0通常用於設置 shell/命令的名稱。

  • 對於每個文件,我們拆分其完整路徑:

    • path="${1%/*}"是刪除文件名部分的完整路徑:${parameter%word}刪除與word模式匹配的後綴;
    • tmp="${1%%${author_string}[^/]*}"擷取每個文件的完整路徑中位於author_string:之前的部分,${parameter%%word}刪除與模式匹配的最長後綴word。我們習慣於忽略作為目錄名稱一部分的[^/]任何出現;author_string
    • before="${tmp##*/}"僅擷取作為文件名一部分的子字元串:${parameter##word}刪除與word模式匹配的最長前綴;
    • after="${1##*${author_string}}"是文件名後面的部分author_string
  • 我們重命名每個文件。

請注意,如果author_string在文件名中重複,則兩次出現之間的任何內容都會失去。

另外,請記住,如果您想逐字匹配它們,則需要轉義(使用 a \)具有特殊模式匹配含義的所有字元。author_string

給定目錄樹:

$ tree .
.
├── testdir
│   ├── title2_author1_date.book
│   ├── title3_author1_date.book
│   └── title4_author2_date.book
├── title1_author1_date.book
└── title5_author2_date.book

這段程式碼:

$ export author_string='author1' new_string='author1'; find . -type f -name "*${author_string}*" -exec sh -c 'path="${1%/*}"; tmp="${1%%${author_string}[^/]*}"; before="${tmp##*/}"; after="${1##*${author_string}}"; echo mv -- "$1" "${path}/${new_string}_${before}${after}"' sh {} \;
mv -- ./title1_author1_date.book ./author1_title1__date.book
mv -- ./testdir/title3_author1_date.book ./testdir/author1_title3__date.book
mv -- ./testdir/title2_author1_date.book ./testdir/author1_title2__date.book

echo當您覺得您已準備好實際重命名文件時,從命令中刪除。


參考:

“The Open Group Base Specifications Issue 7, 2018 edition”(POSIX.1-2017)中的參數擴展

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