linux脚本:使用空格大量重命名文件

时间:2014-08-27 09:12:33

标签: linux shell file-io whitespace

我写了一个脚本,一次重命名几个文件并添加前导零。 该脚本将要重命名的文件作为第一个参数,第二个是新名称,作为第三个参数,您可以提供新的扩展名

只要文件不包含空格(测试asd 1.txt / test 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

我已经尝试过引用/双引用vriables和参数,转义/不转义。

如何解决此案?或者是否有一个更简单的脚本,它将文件重命名,新名称和扩展名作为参数)来重命名多个文件。

2 个答案:

答案 0 :(得分:0)

你明白了,为什么是真的,评论说的是:不要解析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. 用于flaname搜索的模式(默认值:*)
  3. 现在你有一个NULL终止的排序文件名列表,需要阅读并使用它们。下一个循环

    while IFS= read -d $'\0' -r path ; do
        dir=$(dirname "$path")
        file=$(basename "$path")
    
        #do what you want
    
    done < <(sort_files_by_time)
    

    总是双引号&#34; $ variables&#34;什么可以包含空格。

答案 1 :(得分:0)

在Unix中,命令行参数的通配符扩展由shell执行 - 然后传递给程序。

即使文件名中没有空格,此脚本也不起作用。例如,如果有三个文件 song1.mp3 song_2.MP3 song_0003.mpeg3 ,则运行gpRenameWithZero song* test_ mp3脚本将传递五个参数:$ 1将是&#34; song1.mp3&#34;,$ 2将是&#34; song_0003.mpeg3&#34;,$ 3将是&#34; song_2.MP3&#34;,$ 4将是&#34;测试_&#34;而$ 5将是&#34; mp3&#34;。所以你的脚本中的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 命令的第二个参数周围加上双引号。