청소년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'의 출력을 구문 분석하면 안되는 이유!

이것은셸의 파일 이름과 경로 이름: 올바르게 얻는 방법!

예를 들어, 파일 이름에 "-"(대시/하이픈)이 있고 이스케이프 처리되지 않은 경우(앞에 백슬래시("\")를 추가하여) 매개변수로 해석될 수 있습니다.

"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* =

여기에는 몇 가지 문제가 있습니다. 첫째, 쉘 스크립트에서는 일치하는 패턴을 "와일드카드"로 지정할 수 없습니다. 글쎄, 할 수는 있지만 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로 시작하는 이상한 파일 이름이 -손실되지 않도록 해야 합니다.

나는 Glenn의 조언을 어느 정도 받아들여 이렇게 할 것입니다.

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

이 스크립트가 모든 작업을 수행합니다. 왜 안되나요? 쉘이 올바른 파일을 선택하므로 다음을 호출할 필요가 없습니다 ls.

#!/bin/sh
for file in /mnt/backup/bkup_$(date +%Y%m%d)_*
do
    s3cmd put "$file" s3://auto-backup
done
  • 유일한 외부 명령은 입니다 s3cmd.
  • 성명 이 없습니다 if.
  • 유일한 결정 지점은 for루프입니다.
  • 읽기 쉬운.

관련 정보