따라서 기본적으로 작업 디렉터리(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)가 실패하므로 자리 표시자 파일에 아무 것도 출력되지 않습니다.
문법에 관해 더 궁금한 점이 있으시면 언제든지 질문해 주세요.