두 파일을 비교하고 동일하다고 판단되면 쉘 스크립트를 사용하여 사용자에게 중복 파일을 삭제하도록 요청하려면 어떻게 해야 합니까?

두 파일을 비교하고 동일하다고 판단되면 쉘 스크립트를 사용하여 사용자에게 중복 파일을 삭제하도록 요청하려면 어떻게 해야 합니까?

리눅스를 배우고 있는데 이런 질문을 숙제로 하고 있는데 쉘 모드에서 두 파일의 내용을 비교하는 방법에 대한 문제가 해결이 안되네요. (여기서 두 파일 모두 이와 같은 텍스트 콘텐츠를 가지고 있다고 가정할 수 있습니다. 예를 들어 파일 1인 $cat > f1)

$ cat duplicate_file.sh
echo "Enter file 1:"
read file1
echo "Enter file 2:"
read file2
cmp $file1 $file2 > newfile
x=` wc newfile | cut -d" " -f2 `
if [` $x -eq 0 `]
then
rm -i $file2
fi

이 프로그램을 작성했지만 작동하지 않습니다! 그럼 제안사항이 있나요?

답변1

코드의 즉각적인 문제는 읽기 라인의 구문 오류입니다.

if [` $x -eq 0 `]

[및 의 인수는 공백 문자로 ]구분되어야 합니다. 또한 해당 행의 명령 대체는 값을 명령으로 실행 `$x -eq 0`하려고 시도하므로 의미가 없습니다 .$x

또한 스크립트가 공백 문자와 파일 이름 글로빙 패턴을 포함하는 파일 이름을 처리하지 못하게 하는 따옴표 없는 변수 확장 문제도 있습니다.

또한 스크립트는 무조건 파일을 불필요하게 손상시키고( newfile기존 디렉터리 이름인 경우 실패) - 행이 누락되었습니다.newfile#!


사용자에게 대화형으로 파일 경로를 묻는 것은 의미가 없습니다. 사용자는 명령줄에서 셸의 파일 이름 완성을 사용하여 파일의 경로 이름을 두 피연산자로 모두 제공하는 것이 가장 좋습니다.

$ ./script.sh some/path/file1 some/other/path/file2

이 방법으로 스크립트를 실행하면 스크립트에서 "$1"및 이라는 두 개의 경로 이름을 사용할 수 있습니다 "$2".

cmp실용적인 사항임시 파일을 만들지 않고도 이 스크립트 내에서 사용할 수 있습니다. 출력을 리디렉션하는 대신 해당 옵션("silent")을 사용하여 자동으로 만들고 -s종료 상태를 사용하여 두 파일이 동일한지 확인합니다.

스크립트는 다음과 같습니다

#!/bin/sh

if cmp -s -- "$1" "$2"; then
    rm -i -- "$2"
fi

아니면 더 짧게,

#!/bin/sh

cmp -s -- "$1" "$2" && rm -i -- "$2"

rm -i참조하는 파일의 내용이 첫 번째 경로 이름과 동일한 경우 주어진 두 경로 이름 중 두 번째 경로를 호출합니다. --대시로 시작하는 파일 이름을 옵션 세트로 해석하지 않으려면 명령이 필요합니다 .cmprm

이것질문이 스크립트를 제공하는 경우 자신의 스크립트처럼 사용하십시오.동일한 경로 이름이 두 번, 즉, 파일을 자신과 비교하면 삭제를 제안합니다.

따라서 이 두 경로 이름이 두 경로를 모두 참조하는지 확인해야 합니다.다른문서.

두 개의 경로 이름 문자열을 비교하여 이를 수행할 수 있습니다.

#!/bin/sh

if [ "$1" != "$2" ] && cmp -s -- "$1" "$2"; then
    rm -i -- "$2"
fi

./file이는 일부 애플리케이션에서는 충분할 수 있지만 다른 경로(예: vs filevs /path/to/file) 로 지정된 심볼릭 링크나 파일은 고려하지 않습니다 . 대부분의 쉘에서는 비표준(하지만) -ef테스트("동일 파일")는 두 경로 이름이 동일한 파일을 참조하는지 테스트합니다(동일한 inode 번호 및 장치이므로 동일한 파일에 대한 두 개의 하드 링크에 대해서도 true를 반환함).

#!/bin/bash

if ! [ "$1" -ef "$2" ] && cmp -s -- "$1" "$2"; then
    rm -i -- "$2"
fi

또는,

#!/bin/bash

! [ "$1" -ef "$2" ] && cmp -s -- "$1" "$2" && rm -i -- "$2"

그리고 몇 가지 온전성 검사를 수행합니다(또한 -ef테스트를 온전성 검사 섹션으로 이동).

#!/bin/bash

if [ "$#" -ne 2 ]; then
    # did not get exactly two arguments
    printf 'Usage:\n\t%s file1 file2\n' "$0" >&2
    exit 1
elif [ ! -f "$1" ] || [ ! -f "$2" ]; then
    echo 'One of the files does not exist (or is not a regular file)' >&2
    exit 1
elif [ "$1" -ef "$2" ]; then
    printf '%s and %s refer to the same file\n' "$1" "$2" >&2
    exit 1
fi

cmp -s -- "$1" "$2" && rm -i -- "$2"

경로 이름에 공백이 포함되는 경우가 드물지 않기 때문에 인용 변수 확장이 중요합니다(macOS에서는 이것이 일반적임). 또한 큰따옴표 변수 확장은 해당 변수가 쉘 글로빙 패턴으로 해석되는 것을 방지합니다(예를 들어 코드는 이름이 지정된 파일에서 실행되지 않습니다 *). 또한 #!스크립트에서 -line을 적절하게 사용했는지 확인하세요.

숙제라면필요대화형으로 두 파일의 경로 이름을 읽은 다음 합계를 빈 문자열로 read -r설정합니다 . IFS이렇게 하면 공백이나 탭으로 시작하거나 끝나며 문자를 포함하는 경로 이름을 읽을 수 있습니다 \(그러나 개행 문자가 포함된 경로 이름은 지정할 수 없습니다).

#!/bin/bash

IFS= read -p '1st pathname: ' -r p1
IFS= read -p '2nd pathname: ' -r p2

if [ ! -f "$p1" ] || [ ! -f "$p2" ]; then
    echo 'One of the files does not exist (or is not a regular file)' >&2
    exit 1
elif [ "$p1" -ef "$p2" ]; then
    printf '%s and %s refer to the same file\n' "$p1" "$p2" >&2
    exit 1
fi

cmp -s -- "$p1" "$p2" && rm -i -- "$p2"

관련된:


자신의 코드에서와 같이 어떤 시점에서 파일이 비어 있는지 확인해야 하는 경우 wc해당 파일을 호출하지 마세요(전체 파일을 읽어야 하므로 비효율적입니다). 대신 -s테스트를 사용하세요.

if [ -s "$pathname" ]; then
    printf '%s has non-zero size\n' "$pathname"
else
    printf '%s is empty (or does not exist)\n' "$pathname"
fi

man test시스템을 참조하거나 다음을 참조하십시오 .이 유틸리티의 POSIX 표준.

답변2

#!예를 들어 상단에 shebang을 추가하여 시작하십시오 .#!/bin/bash

두 가지 오류가 있습니다.

바꾸다

cmp $file1 $file2 > newfile,

그것은해야한다

cmp -- "$file1" "$file2" > newfile

왜냐하면 이러한 변수의 값에는 공백, 탭, 줄바꿈(문자 $IFS),,, *(와일드카드 문자) 가 포함될 수 있거나 [로 시작할 수 있기 때문입니다.?-

두 번째 오류:

바꾸다

if [` $x -eq 0 `]

그것은해야한다

if [ "$x" -eq 0 ].

그렇지 않으면 오류가 발생합니다

bash: 0: 명령을 찾을 수 없습니다.

또한 파일 이름에 공백이나 와일드카드가 있는 경우 다음과 같아야 합니다.

rm -i -- "$file2"그렇지 않으면 여러 파일이 삭제될 수 있습니다.

답변3

이것이 나의 구현입니다.

#! /bin/bash

echo -n "Enter file1: " 
read file1
echo -n "Enter file2: " 
read file2

if cmp -s -- "$file1" "$file2"
then
      echo same 
      rm -i -- "$file2"
else 
      echo different
fi

var1.txt, var2.txt, 3개의 파일이 있습니다 var3.txt.

  • var1차이점은var2
  • var2동일합니까?var3

이러한 파일에 대해 위 스크립트( com.sh)를 실행하면 다음과 같은 결과가 발생합니다.

$ bash com.sh
Enter file1: var1.txt 
Enter file2: var2.txt 
different

$ bash com.sh
Enter file1: var2.txt 
Enter file2: var3.txt 
same
rm: remove regular file 'var3.txt'?

답변4

다음 코드는 출력이 null비어 있는지 확인합니다. 비어 있으면 파일은 동일하고 그렇지 않으면 파일이 다릅니다.

output=`echo | cmp -b $file1 $file2`

if [[ -z $output ]]
then
    echo "Same"
    rm $file2
else
    echo "Diff"    
fi

관련 정보