簡體   English   中英

linux腳本:使用空格批量重命名文件

[英]linux script: mass rename of files with whitespaces

我編寫了一個腳本來一次重命名幾個文件並添加前導零。 腳本將要重命名的文件作為第一個參數,第二個是新名稱,第三個則是新的擴展名

只要文件不包含空格(測試asd 1.txt /測試asd 2.txt),它實際上就可以工作,因為這樣的輸出是:

~/Desktop $ gpRenameWithZero test\ asd\* test_ mp3
ls: cannot access test: No such file or directory
ls: cannot access asd*: No such file or directory
ls: cannot access test: No such file or directory
ls: cannot access asd*: No such file or directory

這是腳本:

#!/bin/bash
#rename a group of files with adding padding zero: gpRenameWithZero $1=filesToBeRenamed $2=newName $3=filetype: gpRenameWithZero \* newName_ jpg

#123 files -> length of number are 3 digits
numberOfDigits=$(ls $1| wc -l | xargs expr length)

#take extension from command line or take from filename
if [ $# -gt 2 ]; then
    extension=$3
else
    extension=$(ls -rt $1 | head -n 1 | rev | cut -d . -f1 | rev)
fi

#Preview
ls -rt $1 | cat -n | while read n f; do echo mv "$f" `printf "$2%0$numberOfDigits"d".$extension" $n`; done

read -p "Do you wish to rename [y/n]?" yn
case $yn in
    [Yy]* ) ls -rt $1 | cat -n | while read n f; do mv "$f" `printf "$2%0$numberOfDigits"d".$extension" $n`; done;;
    [Nn]* ) ;;
esac

我已經嘗試用引號/雙引號對變量和參數進行轉義/不轉義。

如何解決這種情況? 還是有一個更簡單的腳本,該腳本將要重命名的文件,新名稱和擴展名作為參數來重命名多個文件。

您有個主意,為什么是正確的,評論說了什么:不要解析ls輸出。

在這種情況下,您需要處理以NULL結尾的文件名。 這是許多可以使用這種以NULL終止的字符串的命令。

find命令可以使用arg -print0或完全指定的-print "<format>\\0"輸出以NULL結尾的文件名。

因為您想按修改時間( ls -rt )對文件進行排序(編號),所以需要使用一些技巧。 所以

  • find命令(GNU版本)可以打印出文件修改時間
  • 這次需要對它們進行排序
  • 在切割時間字段后,您將獲得一個文件名的排序列表

例如,可以使用以下命令來實現:

find . -mindepth 1 -maxdepth 1 -name "*" -printf "%T@:%p\0" |sort -zrn |sed -z 's/[^:]*://'
                                                  ^^^^^^^^         ^^^           ^^^^^^^^^^ 
modification-time-in-seconds<colon>path-name<NULL>---+              |                |
            sort the NULL-terminated lines numerically (by time) ---+                |
               remove the <time><colon> part, so only the filename remains ----------+

您可以將上面的內容放入bash函數中以便於使用,例如:

sort_files_by_time() {
        find "${1:-.}" -mindepth 1 -maxdepth 1 -type f -name "${2:-*}" -printf "%T@:%p\0" | sort -zrn | sed -z 's/[^:]*://'
}

上面的函數可以采用兩個可選參數:

  1. 查找的目錄名稱(默認:。)
  2. 搜索名稱的模式(默認值:*)

現在您有了按時間排序的文件名以NULL終止的列表,需要讀取和使用它們。 下一個循環

while IFS= read -d $'\0' -r path ; do
    dir=$(dirname "$path")
    file=$(basename "$path")

    #do what you want

done < <(sort_files_by_time)

總是用雙引號“ $ variables”包含空格。

在Unix中,命令行參數的通配符擴展由外殼程序執行-在傳遞給程序之前。

即使文件名中沒有空格,該腳本也無法使用。 例如,如果有三個文件song1.mp3song_2.MP3song_0003.mpeg3 ,運行gpRenameWithZero song* test_ mp3則腳本將傳遞五個參數:$ 1將是“ song1.mp3”,$ 2將是“ song_0003.mpeg3” ”,$ 3將是“ song_2.MP3”,$ 4將是“ test _”,$ 5將是“ mp3”。 因此,腳本中的$ 1不是您期望的。

您最好將新文件名的前綴和擴展名作為第一個和第二個參數,然后剩下的參數(無論有多少個)將成為文件名。 一個更高級的解決方案甚至可以將它們解析為單獨的選項,以便所有參數都是文件名(即,第一個和第二個參數不會被區別對待)。

#!/bin/sh
# Usage: renameFiles prefix extension {filenames}

# First argument is the new file name prefix

PREFIX=$1
shift

# Second argument is the new file name extension

EXT=$1
shift

# Calculate the maximum width of the number in the new file names

TMP=`echo $# | wc -c`
NUMBER_OF_DIGITS=`expr $TMP - 1`  # Because TMP also counts the newline character

# Process all the remaining arguments as file names

COUNT=1
for FILE in "$@"
do
  NEW_NAME=`printf "${PREFIX}%0${NUMBER_OF_DIGITS}d.${EXT}" $COUNT`

  # If you wish, prompt the user here

  mv "$FILE" "$NEW_NAME"
  COUNT=`expr $COUNT + 1`
done

#EOF

如果任何參數文件名包含空格,則腳本必須使用$ @雙引號和mv命令的第一個參數。 如果前綴和/或擴展名包含空格,則mv命令的第二個參數周圍需要雙引號,腳本才能正常工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM