青年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循環。
  • 易於閱讀。

相關內容