Bash-脚本:在脚本中使用查找和移动无法正常工作

Bash-Scripting: Using find and move inside a script does not work properly

不幸的是,我 运行 在编写 bash 脚本时遇到了问题。

我想要实现的是:

这就是我的脚本的样子。注意这里有一个 NOOB 正在编写脚本!

cat find_and_move.sh 
#!/bin/bash

#keyword
#searchpath
#Smin
#Smax
#season
#destinationpath
#findword
#allfine

while getopts "k:p:d:n:m:x" opt; do

     case $opt in 

        k)
        keyword=$OPTARG ;;
        #get one keyword

        p)
        searchpath=$OPTARG ;;
        #get searchpath ( where to find the keyword )

        n)
        Smin="$(printf '%d' $OPTARG 2>/dev/null)" ;; 
        #convert string to number and save as Smin

        m)
        Smax="$(printf '%d' $OPTARG 2>/dev/null)" ;;
        #convert string to number and save as Smax

        d)
        destinationpath=$OPTARG ;;
        #get destinationpath to copy to

        \?)
        echo "Invalid option: -$OPTARG" >&2 
        exit 1 ;;

        :)
        echo "Option -$OPTARG requires an argument." >&2 
        exit 1 ;; 

     esac
done

#Check if all parameters are set.
if [ -z "$keyword" ]; then echo "keyword is NULL"; 
   else if [ -z "$searchpath" ]; then echo "searchpath is NULL"; 
   else if [ -z "$Smin" ]; then echo "Smin is NULL"; 
   else if [ -z "$Smax" ]; then echo "Smax is NULL"; 
   else if [ -z "$destinationpath" ]; then echo "Destinationpath is NULL"; 
   else echo "ALL PARAMETERS SET";
   allfine="true";

   fi 
   fi 
   fi 
   fi 
 fi


#MAIN: Find and print the result
if [ -z $allfine ]; then echo "allfine is NULL"; 
  else if [ $allfine = "true" ]; then echo "Allfine = true"  

        while [ $Smin -le $Smax ]
        do
                if [ $Smin -le $Smax ] ; 
                   then season="S0$Smin"
                   else season="S$Smin"
                fi
                findword="*$keyword*$season*"
                echo $findword
                echo find $searchpath -iname $findword -type f -print
                find "$searchpath" -iname "$findword" -type f -print
# this search with find works properly

                echo "find $searchpath -iname $findword -type f -exec mv {} $destinationpath/$season \;"
                #find "$searchpath -iname $findword -type f -exec {} $destinationpath/$season \;"
                let Smin++
                sleep 2;
        done;

#If user is satisfied with the result of find&print then order the script to move the files.
        echo "Do you really want to move the files?" 
        read -p "" -n 1 -r
        echo    # (optional) move to a new line
        if [[ ! $REPLY =~ ^[Yy]$ ]]
                then
                exit 1
        fi
        echo "Files will be moved now."
        sleep 2;

        while [ $Smin -le $Smax ]
         do
                 if [ $Smin -le $Smax ] ; 
                    then season="S0$Smin"
                    else season="S$Smin"
                 fi
                 findword="*$keyword*$season*"
                 echo $findword
                 echo find $searchpath -iname $findword -type f -print            
                 find $searchpath -iname $findword -type f -print
#this find search with print works properly
                 echo "find $searchpath -iname $findword -type f -exec mv {} $destinationpath/$season \;"
#the output of echo is correct and works using copy and paste in terminal
                 find "$searchpath" -iname "$findword" -type f -exec mv {} "$destinationpath/$season" \;
#this find -exec mv command seems to be ignored. No error is shown.
                 let Smin++
                 sleep 2;
         done;


        exit 1


  fi
fi

当我用 ./find_and_move.sh -k mykeyword -p mysearchpath -d destinationfolder -n low-number -m high-number 调用该脚本时,一切正常,只是它不移动文件。我也没有收到任何错误消息。

当我将 echo "find $searchpath -iname $findword -type f -exec mv {} $destinationpath/$season \;" 的结果复制并粘贴到终端时,文件的移动没有​​问题。没有 echo 命令似乎被忽略(检查我在脚本中的最后三个评论)。

编辑 4 月 26 日

我在你的脚本里修改了很多东西,你看看:

#!/bin/bash

usage()
{
    echo ""
    echo "Usage: [=10=] -k <keyword> -p <search path> -d <destination folder> -n <value> -m <value>"
    exit 1
}

while getopts "k:p:d:n:m:x" opt
do
    case $opt in
        k)
            #get one keyword
            keyword="$OPTARG"
        ;;
        p)
            #get searchpath ( where to find the keyword )
            searchpath="$OPTARG"
        ;;
        n)
            #convert string to number and save as Smin
            Smin="$OPTARG"
        ;;
        m)
            #convert string to number and save as Smax
            Smax="$OPTARG"
        ;;
        d)
            #get destinationpath to copy to
            destinationpath="$OPTARG"
        ;;
        \?)
            echo "Invalid option: -$OPTARG" >&2
            usage
        ;;
        *)
            echo "Option -$OPTARG requires an argument." >&2
            usage
        ;;
    esac
done

#Check if all parameters are set.
if [ -z "$keyword" ]
then
    echo "keyword is NULL"
    usage
elif [ -z "$searchpath" ]
then
    echo "searchpath is NULL"
    usage
elif [ -z "$Smin" ]
then
    echo "Smin is NULL"
    usage
elif [ -z "$Smax" ]
then
    echo "Smax is NULL"
    usage
elif [ -z "$destinationpath" ]
then
    echo "destinationpath is NULL"
    usage
fi

#DEBUG
echo "keyword=$keyword"
echo "searchpath=$searchpath"
echo "Smin=$Smin"
echo "Smax=$Smax"
echo "destinationpath=$destinationpath"

#MAIN: Find and print the result
whilemin1="$Smin"
while [[ "$whilemin1" -le "$Smax" ]]
do
    echo ""
    season="S0$whilemin1"
    findword="*$keyword*$season*"
    echo "findword=$findword"
    echo "Running: find \"$searchpath\" -iname \"$findword\" -type f -print"
    find "$searchpath" -iname "$findword" -type f -print
    (( whilemin1++ ))
    sleep 2
done

#If user is satisfied with the result of find&print then order the script to move the files.
echo ""
read -p "Do you really want to move the files? " -n 1 -r
if [[ ! $REPLY =~ ^[Yy]$ ]]
then
    echo -e "\nNo files moved."
    #exit 1
else
    echo -e "\nFiles will be moved now."
    sleep 2
fi

whilemin2="$Smin"
while [[ "$whilemin2" -le "$Smax" ]]
do
    echo ""
    season="S0$whilemin2"
    findword="*$keyword*$season*"
    echo "findword=$findword"
    echo "Running: find \"$searchpath\" -iname \"$findword\" -type f -exec mv -t \"./$destinationpath/$season\" {} +"
    find "$searchpath" -iname "$findword" -type f -exec mv -t "./$destinationpath/$season" {} +
    (( whilemin2++ ))
    sleep 2
done
  • 恕我直言,您应该将脚本命名为 find_and_move.bash,因为您的 #! 行是 bash.
  • 缩进整个代码,使代码块更容易看到。
  • 删除了你所有的 ;,不需要。
  • 创建了一个 usage 函数,因为在很多情况下您想要退出命令语法问题。
  • 不需要 printf 将选项值转换为数字,bash 并不关心。如果您对变量值使用数字运算符,它会为您处理。
  • 一起删除了allfine概念,如果任何参数为空,脚本仍然存在。
  • 删除了您的 if then else if then else if ... 并改用 if then elif else fi。更易于阅读。
  • 在您的第一个 while 中,您有两个 find 命令。又是第二个。我把 find ... -print 放在第一个 whilefind ... -exec ... 在第二个
  • 删除了 while 语句中的 if [ $Smin -le $Smax ]。反正这个条件不成立是不可能进入while的,何必再检查
  • 对于read,之前不需要echo,只需将问题作为参数传递给read
  • 删除了旧的 let 命令,替换为 (( )) 语法。
  • 运行 通过站点 https://www.shellcheck.net/ 的代码以确保没有语法问题。

我测试了我认为您希望脚本执行的操作。但是由于你没有提供完整的测试目录和文件结构,可能我没有测试到合适的东西。

注意:评论中关于通过将文件名存储在数组中来避免循环两次的建议是非常正确的,但我不想跳入那个。如果您的文件数量很少并且文件系统更改很少,那么您的脚本将起作用。 YMMV.

编辑说明:它不起作用的原因是第一个 while 增加了 Smin,因此第二个 while 使用那个增加值,因此它永远不会进入 while 循环。修改后的版本现在为每个 while 条件使用新变量。

编辑说明 2find 已修改以避免“文件...已存在”错误消息。 ... -exec mv -t "./$destinationpath/$season" {} +