![두 파일을 비교하고 동일하다고 판단되면 쉘 스크립트를 사용하여 사용자에게 중복 파일을 삭제하도록 요청하려면 어떻게 해야 합니까?](https://linux55.com/image/141855/%EB%91%90%20%ED%8C%8C%EC%9D%BC%EC%9D%84%20%EB%B9%84%EA%B5%90%ED%95%98%EA%B3%A0%20%EB%8F%99%EC%9D%BC%ED%95%98%EB%8B%A4%EA%B3%A0%20%ED%8C%90%EB%8B%A8%EB%90%98%EB%A9%B4%20%EC%89%98%20%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%A5%BC%20%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC%20%EC%82%AC%EC%9A%A9%EC%9E%90%EC%97%90%EA%B2%8C%20%EC%A4%91%EB%B3%B5%20%ED%8C%8C%EC%9D%BC%EC%9D%84%20%EC%82%AD%EC%A0%9C%ED%95%98%EB%8F%84%EB%A1%9D%20%EC%9A%94%EC%B2%AD%ED%95%98%EB%A0%A4%EB%A9%B4%20%EC%96%B4%EB%96%BB%EA%B2%8C%20%ED%95%B4%EC%95%BC%20%ED%95%A9%EB%8B%88%EA%B9%8C%3F.png)
리눅스를 배우고 있는데 이런 질문을 숙제로 하고 있는데 쉘 모드에서 두 파일의 내용을 비교하는 방법에 대한 문제가 해결이 안되네요. (여기서 두 파일 모두 이와 같은 텍스트 콘텐츠를 가지고 있다고 가정할 수 있습니다. 예를 들어 파일 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
참조하는 파일의 내용이 첫 번째 경로 이름과 동일한 경우 주어진 두 경로 이름 중 두 번째 경로를 호출합니다. --
대시로 시작하는 파일 이름을 옵션 세트로 해석하지 않으려면 명령이 필요합니다 .cmp
rm
이것질문이 스크립트를 제공하는 경우 자신의 스크립트처럼 사용하십시오.동일한 경로 이름이 두 번, 즉, 파일을 자신과 비교하면 삭제를 제안합니다.
따라서 이 두 경로 이름이 두 경로를 모두 참조하는지 확인해야 합니다.다른문서.
두 개의 경로 이름 문자열을 비교하여 이를 수행할 수 있습니다.
#!/bin/sh
if [ "$1" != "$2" ] && cmp -s -- "$1" "$2"; then
rm -i -- "$2"
fi
./file
이는 일부 애플리케이션에서는 충분할 수 있지만 다른 경로(예: vs file
vs /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