rm在命令行上工作,但不在脚本中工作


11

当我rm *.old.*在命令行上执行时,它会正确删除,但是当我在脚本的以下部分中执行此操作时,它不会保留所有*.old.*文件。

我的bash脚本出了什么问题:

 for i in ./*; do
    if [[ -f $i ]];  then

        if [[ $i  ==  *.old.* ]]; then
                oldfile=$i
                echo "this file is to be removed: $oldfile"
                rm $oldfile
                exec 2>errorfile
            if [ -s $errorfile ]
            then
                echo "rm failed"
            else
                echo "removed $oldfile!"
            fi
        else
            echo "file with old extension  does not exist"
        fi

        orig=$i
        dest=$i.old
        cp $orig $dest
        echo "Copied $i"

    else
        echo "${i} is not a file"
    fi 
done

Answers:


4

如果我了解您的工作(删除带.old后缀的文件,并复制带.old后缀的任何现有文件),则可以使用find代替:

#!/bin/sh

find . -maxdepth 1 -name \*.old -type f -printf "deleting %P\n" -delete
find . -maxdepth 1 -type f -printf "copying %P to %P.old\n" -exec cp '{}' '{}.old' \;

-maxdepth 0停止在子目录中查找命令,-type f仅查找常规文件;-printf创建消息(%P是找到的文件名)。在-exec cp调用复印功能和'{}'为文件名


14

脚本中可能有各种故障点。首先,rm *.old*将使用globbing创建所有匹配文件的列表,并且可以处理包含空格的文件名。但是,您的脚本会为glob的每个结果分配一个变量,并且无需引用即可执行该操作。如果您的文件名包含空格,那将会中断。例如:

$ ls
'file name with spaces.old.txt'  file.old.txt
$ rm *.old.*   ## works: both files are deleted

$ touch "file.old.txt" "file name with spaces.old.txt"
$ for i in ./*; do oldfile=$i; rm -v $oldfile; done
rm: cannot remove './file': No such file or directory
rm: cannot remove 'name': No such file or directory
rm: cannot remove 'with': No such file or directory
rm: cannot remove 'spaces.old.txt': No such file or directory
removed './file.old.txt'

如您所见,文件名中带有空格的循环失败。要正确执行此操作,您需要引用该变量:

$ for i in ./*; do oldfile="$i"; rm -v "$oldfile"; done
removed './file name with spaces.old.txt'
removed './file.old.txt'

相同的问题适用$i于脚本中几乎所有的用法。您应该始终引用变量

下一个可能的问题是,您似乎期望*.old.*与扩展名为的文件匹配.old。没有。它匹配“ 0个或多个字符”(*),然后是.,然后是“旧”,然后是另一个.,然后又是“ 0个或多个字符”。这意味着它将不会匹配file.old,而只会匹配`file.old.foo:

$ ls
file.old  file.old.foo
$ for i in *; do if [[ "$i" == *.old.* ]]; then echo $i; fi; done
file.old.foo     

因此,没有对手file.old。无论如何,您的脚本都比需要的复杂得多。尝试以下一项:

#!/bin/bash

for i in *; do
    if [[ -f "$i" ]];  then
        if [[ "$i"  ==  *.old ]]; then
            rm -v "$i" || echo "rm failed for $i"
        else
            echo "$i doesn't have an .old extension"
        fi
        cp -v "$i" "$i".old
    else
        echo "$i is not a file"
    fi 
done

请注意,我-vrm和cp which does the same thing as what you were doing with yourecho`语句中添加了内容。

这不是完美的,因为例如当您找到时,file.old它将被删除,并且此脚本以后将尝试复制它,并且由于文件不再存在而失败。但是,您还没有解释脚本实际上试图执行的操作,因此除非您告诉我们您真正想要完成的操作,否则我无法为您解决该问题。

如果您要i)删除所有带有.old扩展名的文件,并且ii)将.old扩展名添加到没有扩展名的任何现有文件中,那么您真正需要的是:

#!/bin/bash

for i in *.old; do
    if [[ -f "$i" ]]; then
        rm -v "$i" || echo "rm failed for $i"
    else
        echo "$i is not a file"
    fi 
done
## All the ,old files have been removed at this point
## copy the rest
for i in *; do
    if [[ -f "$i" ]]; then
        ## the -v makes cp report copied files
        cp -v "$i" "$i".old
    fi
done

我正在尝试将文件备份到file.old,但同时将以.old.old或.old.old.old或.old.old.old等结尾的所有文件rm *.old.*都删除。在命令行上,我使用它删除了这些文件但不是file.old备份文件。我正在尝试在脚本中执行此操作。谢谢

1
@Don,请编辑您的问题并详细解释。包括示例文件名以及在脚本运行后您想对它们进行的处理。理想情况下,聊天并在此处ping我,以便我们进行讨论。
terdon's

8

唯一的情况下rm $oldfile可能会失败时,你在文件名中包含的任何字符IFS(空格,制表符,换行符)或任何水珠字符(*?[])。

如果存在任何字符,IFS则外壳程序将根据变量扩展上是否存在通配符路径名扩展来执行单词拆分。

因此,例如,如果文件名为foo bar.old.,则变量oldfile将包含foo bar.old.

当您这样做时:

rm $oldfile

shell首先将oldfileon space 的展开分为两个单词,foobar.old.。因此,命令变为:

rm foo bar.old.

这显然会导致意外的结果。顺便说一句,如果您有任何通配符运算符(*?[]在扩展),那么路径扩展也会被完成。

您需要引用变量以获得所需的结果:

rm "$oldfile"

现在,将不会进行任何单词拆分或路径名扩展,因此您应该获得所需的结果,即所需的文件将被删除。如果碰巧以开头的任何文件名-,请执行以下操作:

rm -- "$oldfile"

您可能会问,为什么在内部使用时我们不需要引用变量[[,原因[[bash它是一个关键字,它在内部处理变量扩展并保留扩展文字。


现在,有几点要点:

  • 您应该exec 2>errorfilerm命令之前重定向STDERR(),否则[[ -s errorfile ]]测试会产生误报

  • 您已使用[ -s $errorfile ],正在使用变量扩展$errorfile,如果errorfile未在任何地方定义变量,则为NUL 。也许您的意思是[ -s errorfile ]基于STDERR重定向

  • 如果errorfile定义了变量,则在使用时[ -s $errorfile ],它将再次阻塞和的上述情况,IFS因为与不同[[[它不是由内部处理的bash

  • 在脚本的后半部分,您尝试cp使用已经删除的文件(同样不引用变量),这没有任何意义,您应该检查该卡盘并根据目标进行必要的更正。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.