SHELL: 출력이 예상한 것과 다릅니다.

SHELL: 출력이 예상한 것과 다릅니다.

저는 다음 과제를 수행 중이며 내 프로그램에 대한 질문이 있습니다.

아래에 설명된 대로 파일을 복사하는 쉘 스크립트를 작성하십시오. 접미사는 명령줄 인수로 전송되어야 합니다. 지정된 접미사가 적합한 현재 디렉터리의 각 파일에 대해 사용자에게 해당 파일을 저장해야 하는지 묻는 메시지가 표시됩니다. 대답이 '예'이면 파일을 백업 디렉터리에 복사해야 합니다. 디렉터리가 존재하지 않으면 새로 만들어야 합니다.

이것이 내가 한 일입니다:

#!/bin/sh

usage() {
  echo "Usage : prog.sh <POSTFIX> " >&2
  exit 1
}

if [ $# -ne 1 ]; then
 usage
fi

list=$(ls)

for name in $list; do

  case $name in

  *.$@)
    printf "Do you want to save the file ?\n"
    read answer

    case $answer in
     Yes|yes|y)
      ls backup 2>/dev/null || mkdir backup
      mv $name backup
      ;;
     No|no|n);;
    esac ;;
  esac
done

다음 폴더가 있다고 가정해 보겠습니다. (백업 디렉터리로 이동됩니다.)

bar.txt foobar.txt foo.txt mbar.txt

이것은 내 결과입니다.

Do you want to save the file ? 
y
Do you want to save the file ? 
y
bar.txt                           // Why is it printing the file during the output ?
Do you want to save the file ? 
y
bar.txt  foobar.txt               // ??
Do you want to save the file ? 
y                                 
bar.txt  foobar.txt  foo.txt     // ??

ls backup 2>/dev/null || mkdir backup(대신에 ) 이렇게 쓸 수 있다는 걸 알아요

  if [ ! -d backup ] ; then
           mkdir backup
   fi

하지만 내 프로그램이 출력 중에 백업으로 이동된 파일을 인쇄하는 이유를 알고 싶습니다.

답변1

ls backup 2>/dev/null디렉토리로 이동한 각 파일에 대해 작업을 수행했기 때문에 해당 파일이 backup다음에 ls표시됩니다 .

그런데 전체 스크립트를 다음과 같은 단일 명령으로 바꿀 수 있습니다 rsync.

rsync --include='*.{txt,csv,xyz}' /path/to/source/* /path/to/backup/

바라보다man rsync동기화 후 삭제 방법에 대해 자세히 알아보세요.

답변2

다음 줄 때문입니다.

ls backup 2>/dev/null

stdout이 아닌 stderr만 리디렉션합니다. 다음을 수행해야 합니다.

ls backup >/dev/null 2>&1 || mkdir backup

그렇지 않으면:

mkdir -p backup

또한 shellcheck에서 표시되는 경고에도 주의를 기울여야 합니다.

$ shellcheck ./p.sh

In ./p.sh line 18:
            read answer
            ^--^ SC2162: read without -r will mangle backslashes.


In ./p.sh line 24:
                    mv $name backup
                       ^---^ SC2086: Double quote to prevent globbing and word splitting.

Did you mean:
                    mv "$name" backup

For more information:
  https://www.shellcheck.net/wiki/SC2086 -- Double quote to prevent globbing ...
  https://www.shellcheck.net/wiki/SC2162 -- read without -r will mangle backs...

답변3

Bash가 허용된다면 다음과 같이 할 것입니다:

#!/usr/bin/env bash

if (( $# == 0 )); then
    echo "usage: ${0##*/} extension ..." >&2
    exit 1
fi

dir=./backup
mkdir -p "$dir"

# if the script is called like `script.sh foo bar baz`
# then $pattern is `@(*foo|*bar|*baz)`
pattern=$(
    set -- "${@/#/*}"
    IFS='|'
    echo "@($*)"
)

shopt -s nocasematch

for file in *; do       
    # right-hand side is specifically unquoted
    if [[ "$file" == $pattern ]]; then
        read -p "Move file '$file'? [y/N] " ans
        if [[ "$ans" == Y* ]]; then
            mv -i -v "$file" "$dir"
        fi
    fi
done

과제이기 때문에 구체적인 질문을 하기 전에 이해가 안 되는 부분을 좀 조사해 보세요. 이것배쉬 매뉴얼좋은 출발점입니다.

관련 정보