青年MMV

青年MMV

$ sh 备份到 s3.sh

backup-to-s3.sh: 11: [: bkup_20151106_150532.zip: unexpected operator
backup-to-s3.sh: 11: [: bkup_20151106_150532.zip: unexpected operator
backup-to-s3.sh: 11: [: bkup_20151106_150532.zip: unexpected operator
backup-to-s3.sh: 11: [: bkup_20151106_150532.zip: unexpected operator
backup-to-s3.sh: 11: [: bkup_20151106_150532.zip: unexpected operator
backup-to-s3.sh: 11: [: bkup_20151106_150532.zip: unexpected operator

ubuntu@accretive-staging-32gb-ephemeral:~$ cat backup-to-s3.sh

#Script to move /home/ubuntu/backup folder  to S3://auto-backup
#Author Ashish Karpe
cd /mnt/backup
filename="bkup_$(date +%Y%m%d_)"
/bin/ls -alF | awk '{ print $9 }'  > /tmp/file

for i in $(cat /tmp/file); do
#       echo $i;
#       read a;
#       echo $filename;
        if [ $filename* = $i ]
        then
                echo "Copying " $i "to S3://auto-backup";
                s3cmd put $i s3://auto-backup

            fi

done

答案1

  1. 不要用于for迭代文件的行,使用

    while IFS= read -r line; do ...; done < filename
    
  2. 你根本不需要将ls输出通过管道传输到文件,尤其使用-F

  3. 使用bash[[ x == y ]]进行模式比较,模式在右侧:
#!/bin/bash
cd /mnt/backup
prefix="bkup_$(date +%Y%m%d_)"

for file in * .*; do
    [[ -f $file ]] || continue    # skip things like directories and soft links
    if [[ $file == $prefix* ]]; then
        echo "Copying " $file "to S3://auto-backup";
        s3cmd put $file s3://auto-backup
    fi
done < /tmp/file

答案2

即使您将“ls”的输出转储到文件中并解析,您还是间接解析了“ls”的输出,这要么是有问题的,要么是一个非常糟糕的主意,要么是错误的!取决于你问的是谁。

这是为什么你不应该解析 'ls' 的输出

这是Shell 中的文件名和路径名:如何正确执行

例如,如果一个文件的文件名中有一个“-”(破折号/连字符)且未转义(通过在其前面加上反斜杠(“\”)),则它可能会被解释为参数。

避免解析“ls”可能很简单:

find . -maxdepth 1 -iname "*"
.
./dont_parse_ls.sh
./array.dat
./.bashrc
./BASH.Indirect.Reference.sh
./basharray.sh
./.forever

结果是一样的

/bin/ls -alF | awk '{ print $9 }'

./
../
.bashrc
.forever/
BASH.Indirect.Reference.sh
array.dat
basharray.sh*
dont_parse_ls.sh

青年MMV

答案3

剧本中至少有两个主要问题。您的根本问题是片段:

if [ $filename* =

这有一些问题。首先,在 shell 脚本中,您不能“通配”匹配模式。好吧,你可以,但如果 fileglob 产生多个匹配项,你将同时获得它们,在这种情况下,“[”程序(是的,它是一个程序)将尝试评估:

filename1 filename2 filename3 = $i

当且仅当 fileglob 恰好扩展为一个文件名时它才有效,但你很难保证这一点。在您的情况下, $filename 扩展为至少一个文件,但您应该意识到情况并非总是如此。如果“$file*”扩展为根本没有文件,您可能(取决于 shopt 设置)得到空字符串:

= $i

这将导致[失败。然而,通过正确的商店,您会得到:

backup-2014-whatever* = $i

随着*比较的一部分。

第二个基本问题是-F中参数的使用ls。这告诉 ls 在文件名后附加几个字符之一,具体取决于文件是否是可执行文件、软链接等。

NetScr1be 是有道理的,但是看,你不必遵循 NetScr1be 的建议并且永远不要使用ls......只是不要使用ls -l。相反,使用ls -1它只会在单列中打印文件的名称,没有多余的装饰。 (对于非常大的目录,它会对它们进行排序,这可能是一个问题,在这种情况下有一个不排序选项;或者使用 find。)

为了更安全,您的变量应该用双引号引起来,并且 LHS 和 RHS 都以虚拟字符为前缀,以确保以 a 开头的奇怪文件名-不会丢失。

我会或多或少地采纳格伦的建议,并这样做:

command ls -1 | while read file; do
    if [ x"$file" = x"$filename" ]]; then 
        echo Do Work Here
    fi
done

我就是这样这样做,但格伦好心地告诉我,我真的应该这样做他的方式:

for file in *; do 
    if [[ $file == $filename ]]; then ...

答案4

这个脚本完成了一切。为什么不是这个? shell 将为您选择正确的文件,因此无需调用ls

#!/bin/sh
for file in /mnt/backup/bkup_$(date +%Y%m%d)_*
do
    s3cmd put "$file" s3://auto-backup
done
  • 唯一的外部命令是s3cmd.
  • 没有if任何声明。
  • 唯一的决策点是for循环。
  • 易于阅读。

相关内容