스크립트가 배열의 올바른 요소를 올바르게 인쇄하지 않습니다.

스크립트가 배열의 올바른 요소를 올바르게 인쇄하지 않습니다.

따라서 기본적으로 작업 디렉터리(file.00.txt에서 file.24.txt로 명명)에서 일부 특정 파일을 확인하기 위해 bash 스크립트를 작성해야 합니다. 문제는 그 중 3개가 동일하다는 것입니다. 내 임무는 어느 3개가 동일한지 알려주는 스크립트를 만드는 것입니다.

이게 내 코드야

#!/bin/bash 
f0=file.00.txt
f1=file.01.txt
f2=file.02.txt
f3=file.03.txt
f4=file.04.txt
f5=file.05.txt
f6=file.06.txt
f7=file.07.txt
f8=file.08.txt
f9=file.09.txt
f10=file.10.txt
f11=file.11.txt
f12=file.12.txt
f13=file.13.txt
f14=file.14.txt
f15=file.15.txt
f16=file.16.txt
f17=file.17.txt
f18=file.18.txt
f19=file.19.txt
f20=file.20.txt
f21=file.21.txt
f22=file.22.txt
f23=file.23.txt
f24=file.24.txt

array=($f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15 $f16 $f17 $f18 $f19 $f20 $f21 $f22 $f23 $f24)

i=0
touch placeholder

while [ $i -lt ${#array} ]
do
    DIFF=$(diff ${array[i]} ${array[i+1]})
    if [ "$DIFF" = "" ]
    then
        echo "${array[i]} y ${array[i+1]}" >> placeholder
    fi
i=$((i+1))
done

    cat placeholder 

이 코드의 아이디어는 각 파일을 배열의 다음 파일과 비교한 다음 동일한 파일을 자리 표시자라는 파일에 저장하고 마지막으로 cat 명령을 사용하여 파일의 내용을 표시하는 것입니다.

그러나 스크립트를 실행할 때마다 메시지가 나타납니다.

file.00.txt y file.00.txt
file.01.txt y file.01.txt
file.02.txt y file.02.txt

각 파일에 대해서도 마찬가지입니다. 분명히 사용하고 있기 때문에 이런 일이 발생해서는 안됩니다.

echo "${array[i]} y ${array[i+1]}" >> placeholder

두 가지 입장 모두에 응답하십시오. 왜 이런 일이 발생합니까? 이 문제를 어떻게 해결할 수 있나요?

이 문제를 어떻게 해결할 수 있나요?

답변1

코드에서 이상해 보이는 결과가 나오는 이유는 스크립트가다음에 추가출력 파일에. 이는 이전 코드(현재 수정됨)에 일부 버그가 있었을 수 있지만 출력 파일이 스크립트에 의해 삭제되거나 비워지지 않기 때문에 출력 파일에서 해당 실행의 출력을 계속 볼 수 있음을 의미합니다.


스크립트를 다음과 같이 단축할 수 있습니다.

#!/bin/bash

array=( file.*.txt )

for name in "${array[@]}"; do
    if [ -n "$prev_name" ] && cmp -s "$prev_name" "$name"
    then
        printf '%s y %s\n' "$prev_name" "$name"
    fi

    prev_name=$name
done

이는 와일드카드 패턴을 사용하여 패턴과 일치하는 파일 이름으로 배열을 채웁니다.

그런 다음 .을 사용하여 배열에서 서로 옆에 있는 파일 이름을 비교하여 이름을 반복합니다 cmp -s. 유틸리티 cmp가 종료되고 다음이 표시됩니다.진짜비교되는 두 파일의 내용이 동일한 경우 종료 상태입니다.

$prev_name이 루프는 배열의 이전 파일 이름을 저장하는 데 사용됩니다 . 루프의 첫 번째 반복에서 이 변수는 비어 있으므로 파일의 실제 비교를 건너뜁니다.


당신은 무엇일지도 모른다예상되는글쓰기는 이중주기입니다. 그것은 마치

for nameA in "${array[@]}"; do
    for nameB in "${array[@]}"; do
        if [ "$nameA" != "$nameB" ] && cmp -s "$nameA" "$nameB"
        then
            printf '%s y %s\n' "$nameA" "$nameB"
        fi
    done
done

A하지만 이것도 마찬가지 일 것이다B 그리고 B, A호출 수는 cmp관련된 파일 수에 따라 2차적으로 증가하며 리소스 집약적입니다(디스크에서 읽기파일당배열에 있는 파일 이름만큼) 속도가 느립니다.


동일한 내용이 포함된 파일 세트를 찾는 일반적인 방법은 다음과 같습니다 fdupes.

$ fdupes --sameline .
./file.1.txt ./file.2.txt ./file.7.txt

없이 비슷한 작업을 수행하려면 fdupes다음을 사용하여 각 파일의 체크섬을 계산하고 비교하면 됩니다 md5sum.

#!/bin/bash

declare -A names count

while read -r cksum name; do
    names[$cksum]+=${names[$cksum]:+,}$name
    count[$cksum]=$(( count[$cksum] + 1 ))
done < <( md5sum file.*.txt )

for cksum in "${!count[@]}"; do
    if [ "${count[$cksum]}" -gt 1 ]; then
        printf '%s\n' "${names[$cksum]}"
    fi
done

md5sum첫 번째 루프는 모든 관련 파일의 실행 출력을 읽습니다. 의 출력은 md5sum다음과 유사할 수 있습니다.

897316929176464ebc9ad085f31e7284  file.1.txt
8c9eb686bf3eb5bd83d9373eadf6504b  file.10.txt
897316929176464ebc9ad085f31e7284  file.2.txt
26ab0db90d72e28ad0ba1e22ee510510  file.3.txt
84bc3da1b3e33a18e8d5e1bdd7a18d7a  file.4.txt
aa6ed9e0f26a6eba784aae8267df1951  file.5.txt
6d7fce9fee471194aa8b5b6e47267f03  file.6.txt
897316929176464ebc9ad085f31e7284  file.7.txt
c30f7472766d25af1dc80b3ffc9a58c7  file.8.txt
9ae0ea9e3c9c6e1b9b6252c8395efdc1  file.9.txt

첫 번째 열의 체크섬을 에서 읽고 cksum, 파일 이름을 에서 읽습니다 name.

첫 번째 루프에서는 체크섬으로 색인화된 연관 배열의 항목에 이름을 추가합니다. 여기서 할당이 수행되는 방식에 names[$cksum]따라 필요한 경우 각 새 이름 앞에 쉼표를 추가합니다(항목에 이미 다른 이름이 포함된 경우). 그런 다음 특정 체크섬이 표시된 횟수를 업데이트합니다(두 번째 루프에서 사용됩니다).

두 번째 루프에서는 체크섬( "${!count[@]}"연관 배열의 키(체크섬) 목록으로 확장됨 count)을 확인하고 각 체크섬에 대해 해당 개수가 1보다 큰지 테스트합니다. 이는 중복된 파일을 찾았다는 의미입니다. 세 개의 동일한 파일 그룹이 있는 경우 이를 -eq 3대신 사용할 수 있습니다 -gt 1). 그렇다면 해당 체크섬과 관련된 이름을 인쇄합니다.

테스트해보세요:

$ bash script.sh
file.1.txt,file.2.txt,file.7.txt

답변2

이는 원하는 작업을 수행하는 보다 효율적인 방법입니다. 더 명확하게 하기 위해 더 작은 샘플 세트를 사용하고 있습니다.

#!/bin/bash

# clear placeholder
printf "Files with no diff:\n" > placeholder

# set up sample data
echo "one" > file.00.txt
echo "one" > file.01.txt
echo "foo" > file.02.txt
echo "bar" > file.03.txt
echo "two" > file.04.txt
echo "two" > file.05.txt 

# generate array
i=0
while [ $i -lt 6 ]; do    
    array+=( file.`printf %02d $i`.txt )
    ((i++))
done

i=0
while [ $i -lt 5 ]; do
    diff --brief ${array[i]} ${array[i+1]} && \
    echo "${array[i]} ${array[i+1]}" >> placeholder 
    ((i++))
done

결과:

$ sh ./test.sh 
Files file.01.txt and file.02.txt differ
Files file.02.txt and file.03.txt differ
Files file.03.txt and file.04.txt differ
$ cat placeholder 
Files with no diff:
file.00.txt file.01.txt
file.04.txt file.05.txt

실제로 데이터가 이미 있는 경우에는 샘플 데이터를 생성할 필요가 없습니다.

코드 설명:

루프(Bash)에서 배열을 구축하는 것은 이미 알고 있는 방식을 반복하되 array+=요소를 추가하는 표기법을 사용하여 수행할 수 있습니다.

이것은 ((++))분명히 카운터를 증가시킬 것입니다.

나는 diff를 수행할 때 이 옵션을 사용합니다 --brief. diff매뉴얼 페이지를 읽으면 --brief차이점이 발견된 경우에만 출력을 인쇄하라는 내용이 나와 있습니다. 따라서 diff 명령은성공차이점이 발견되지 않은 경우.

(AND) 표기법을 사용하면 이 코드는 &&파일이 비교되는 파일 이름을 에코 합니다.placeholder만약에 그리고 만약에diff명령은 출력을 생성하지 않습니다.

만약 있다면파일 간의 차이점, diff차이점을 터미널에 출력합니다. 이로 인해 &&(AND)가 실패하므로 자리 표시자 파일에 아무 것도 출력되지 않습니다.

문법에 관해 더 궁금한 점이 있으시면 언제든지 질문해 주세요.

관련 정보