首页 > 解决方案 > Bash / sh:移动文件夹+子文件夹隐蔽地重命名文件(如果存在)

问题描述

我正在尝试创建一个 bash 脚本,它将所有文件递归地从源文件夹移动到目标文件夹,并简单地重命名文件(如果它们已经存在)。与 M$ Windows 的方式类似,当文件存在时,它会使用"<filemame> (X).<ext>"等自动重命名,但所有文件除外。

我已经创建了以下内容,它适用于几乎所有场景,除非文件夹的名称中有 (.) 句点并且该文件夹中的文件没有扩展名(名称中没有句点)。

例如文件夹路径文件,例如:"./oldfolder/this.folder/filenamewithoutextension"

我得到(错误地): "./newfolder/this (1).folder/filenamewithoutextension"

如果"./newfolder/this.folder/filenamewithoutextension"已存在于目标位置 ( ./newfolder),

而不是正确命名新文件:"./oldfolder/this.folder/filenamewithoutextension (1)"


#!/bin/bash
source=$1 ; target=$2 ;
if [ "$source" != "" ] && [ "$target" != "" ] ; then
        #recursive file search
        find "$source" -type f -exec bash -c '
                #setup variables
                oldfile="$1" ; osource='"${source}"' ; otarget='"${target}"' ;
                #set new target filename with target path
                newfile="${oldfile/${osource}/${otarget}}" ;
                #check if file already exists at target
                [ -f "${newfile}" ] && {
                        #get the filename and fileextension for numbering - ISSUE HERE?
                        filename="${newfile%/}" ; newfileext="${newfile##*.}" ;
                        #compare filename and file extension for missing extension
                        if [ "$filename" == "$newfileext" ] ; then 
                               #filename has no ext - perhaps fix the folder with a period issue here?
                               newfileext="" ; 
                        else 
                               newfileext=".$newfileext" ; 
                        fi
                        #existing files counter
                        cnt=1 ; while [ -f "${newfile%.*} (${cnt})${newfileext}" ] ; do ((cnt+=1)); done
                        #set new filename with counter - New Name created here *** Needs re-work, as folder with a period = fail
                        newfile="${newfile%.*} (${cnt})${newfileext}";
                }
                #show mv command
                echo "mv \"$oldfile\" \"${newfile}\""
        ' _ {} \;
else
        echo "Requires source and target folders";
fi

我怀疑问题是,如何正确识别文件名和扩展名,在这一行中找到:

filename="${newfile%/}" ; newfileext="${newfile##*.}"它不能正确识别文件名(文件总是在最后一个 / 之后)。

关于如何使其正常工作的任何建议?

更新:只是一些完成说明 - 问题修复:

  1. 最初拆分每个完整路径文件名:路径-文件名-(可选ext)
  2. 重构全路径文件名:路径-文件名-计数器-(可选ext)
  3. 修复了文件移动以确保使用 mkdir -p 存在目录结构(如果目标位置中不存在新文件夹,mv 不会创建新文件夹)。

标签: bash

解决方案


也许你可以试试这个?

filename="${newfile##*/}" ; newfileext="${filename#*.}"
  • 第一个模式意味着:删除最长的前缀(以贪婪的方式)直到最后一个/.
  • 第二个:删除直到第一个点的前缀(这里似乎不需要贪婪模式) - 正如您已经注意到的,如果文件名不包含点,您将得到newfileext == filename......</li>

示例会话:

newfile='./oldfolder/this.folder/filenamewithoutextension'
filename="${newfile##*/}"; newfileext="${filename#*.}"
printf "%s\n" "$filename"
#→ filenamewithoutextension
printf "%s\n" "$newfileext"
#→ filenamewithoutextension

newfile='./oldfolder/this.folder/file.tar.gz'
filename="${newfile##*/}"; newfileext="${filename#*.}"
printf "%s\n" "$filename"
#→ file.tar.gz
printf "%s\n" "$newfileext"
#→ tar.gz

推荐阅读