更好的方法

更好的方法

我有这个简单的代码,可以在清理时创建 .bak 文件。当我再次清理时,bak 文件应该被删除,并且没有 .bak 文件。 bak 它应该回显“没有 .bak”,但它只执行 if 条件。这是代码:

#!/bin/bash
chmod u+x sources/*
if [ "$1" == "clean" ]
then

    if [ -f `sources/*.bak` ]
    then        
       rm sources/*.bak

    else
        echo "there's no .bak files"
    fi

elif ["" == "$1"]
then

echo "This script makes a backup for each .c or .h file in sources directory"

target_files=`echo -n $(ls sources/{*.c,*.h})`
echo
echo "Starting to backup: $target_files"

for i in $target_files 
do 
  cp "$i" "$i".bak
done

echo
echo "The following backup files were created: `echo -n $(ls sources/*.bak)`"
echo
echo "Done"

fi 

答案1

问题是线

if [ -f `sources/*.bak` ]

反引号`在 bash 中具有特殊含义:它们用于计算命令并返回其输出。

例如,如果您的用户名是弗罗德尔然后

if [ -f `whoami` ]

将检查是否存在名为frodl.

因此,如果您编写sources/*.bak,它会首先尝试 glob 该术语,但由于目录sources/*.bak中没有具有扩展名的文件,因此该术语不会被扩展。然后它会尝试运行字面术语,这不是有效的命令(实际上你sources/.baksources/*.bak有一个名为sources/*.bak(开头带有星号的文件名;颤抖!)的文件,但似乎您没有。然而,这个文件会有一个.bak扩展名,这是我们之前排除的。)

如果您确实有一个 file sources/deletemyharddisk.bak,那么该术语sources/*.bak将扩展为该字符串,然后尝试执行它(可能会删除您的硬盘)。

所以你需要做的就是使用普通的引号。

backupfiles=sources/*.bak
if [ "x${backupfiles}" = "xsources/*.bak" ]; then
     echo "no .bak files" 1>&2
else
     echo "there are .bak files"...
fi

这将首先尝试将术语扩展sources/*.bakbackupfiles变量中。如果有任何bak文件,这将成为所有文件名的字符串;如果没有,这将保留未展开的字符串。如果然后将结果与文字(未扩展)进行比较,sources/*.bak您可以判断是否发生了扩展(因为有匹配的文件)。

更好的方法

然而,没有理由首先检查是否有文件然后删除它们。一种更简单的方法是删除与给定模式匹配的所有文件。 find可以为您做到这一点:

find sources/ -maxdepth 1 -type f -name "*.bak" -delete

(这将在目录的第一级 ( -maxdepth 1) 中搜索以( ) 结尾sources/的文件(-type f; 而不是目录或符号链接或其他内容),然后删除它们 ( ).bak-name "*.bak"-delete

不解析ls

您的代码的另一个问题是

target_files=`echo -n $(ls sources/{*.c,*.h})`
for i in $target_files 
...

你应该从不解析的输出ls

而是使用类似的东西

 for i in sources/*.c sources/*h
 do
   #...
 done

相关内容