찾기 | xargs shasum은 체크섬 파일 자체의 체크섬을 조기에 생성하고 검사 할 때 실패합니다


10

내 문제 (와의 스크립트에서 #!/bin/sh)는 다음과 같습니다. 보관 목적으로 디렉토리의 모든 파일을 체크섬하려고합니다. 모든 파일 이름을 가진 체크섬 (내 경우에는 sha1) 파일은 동일한 디렉토리에 있어야합니다. ~/test파일 f1과 디렉토리가 있다고 가정 해 봅시다 f2.

mkdir ~/test
cd ~/test
echo "hello" > f1
echo "world" > f2

이제 체크섬을 계산하여

find -maxdepth 1 -type f -printf '%P\n' | xargs shasum

내가 원하는 것을 정확하게 수행하면 현재 디렉토리의 모든 파일 만 나열하고 sha1 합계를 계산합니다 (maxdepth는 나중에 변경 될 수 있음). STDOUT의 출력은 다음과 같습니다.

f572d396fae9206628714fb2ce00f72e94f2258f  f1
9591818c07e900db7e1e0bc4b884c945e6a61b24  f2

불행히도,이 파일을 파일에 저장하려고 할 때

find -maxdepth 1 -type f -printf '%P\n' | xargs shasum > sums.sha1

결과 파일은 체크섬 자체를 표시합니다.

da39a3ee5e6b4b0d3255bfef95601890afd80709  sums.sha1
f572d396fae9206628714fb2ce00f72e94f2258f  f1
9591818c07e900db7e1e0bc4b884c945e6a61b24  f2  

따라서 shasum --check마지막 합계를 저장할 때 추가 파일 수정의 명백한 문제 때문에 나중에 실패합니다 .

나는 주변을 둘러보고 -pfor 플래그를 사용 xargs하여 find 명령을 실행하기 전에 어떻게 든 출력 파일을 생성한다는 것을 알았습니다. 따라서 추가 파일이 발견되어 체크섬됩니다 ...

해결 방법으로 체크섬을 다른 위치 (temp 디렉토리를 통해 mktemp)에 저장하거나 구체적으로 찾기에서 제외시킬 수는 있지만 그것이 어떻게 작동하는지 왜 이해하고 싶습니다. 예를 들어 첫 번째 명령으로 출력 파일이 이미 디스크에 있는지 확인하면 정답을 얻지 못할 것입니다 ...


8
명령이 먼저 실행 xargs되기 전에 쉘이 모든 입력, 출력 및 파이프를 재 지정하므로 find출력 파일이 시작될 때 이미 존재 하기 때문에이 파일을 작성하는 것은 쉘 자체 가 아닙니다 . 사용 -exec하는 대신 :find -maxdepth 1 -type f -exec sh -c 'shasum "$@" > sums.sha1' {} +
jimmij

@ jimmij, 여러 번의 sh호출이 필요한 경우에도 작동하지 않을 수 있습니다. $0before에 대한 인수가 필요합니다 {}.
Stéphane Chazelas 2016 년

@jimmij 제안한 다른 답변 tee이 사라졌습니다? 나는 그것을 시도하고 잘 작동하며,를 추가하여 STDOUT을 억제했습니다 1>/dev/null. 답변에 문제가 있었습니까, 아니면 버그입니까?
user121391 2016 년

@ user121391 스테판은 때때로 경쟁 조건 문제가있을 수 있다고 지적했다. 나는 당신이 볼 수 있도록 잠시 동안 삭제를 취소했지만 목록에 많은 파일이 있으면 명령이 잘못 될 수 있습니다.
jimmij

@ jimmij 아, 알겠습니다. 이 문제가 발생할 수 있다고 잘 알려져 있지 않기 때문에 문제에 대한 경고로 접두사를 붙이면 도움이 될 수 있습니다. 그렇지 않으면 반복 실행에 이전 파일과 Anthon이 포함되어 있으면 덮어 쓸 경우에 대한 답변을 수락했을 것입니다.
user121391 2016 년

답변:


12

다음을 xargs사용하여 파일에 도달하지 못하게 할 수 있습니다 .

find . -maxdepth 1 -type f ! -name sums.sha1 -printf '%P\n' |
  xargs -r shasum -- > sums.sha1

공백이나 줄 바꿈 또는 따옴표 또는 백 슬래시가있는 파일 이름의 문제를 방지하기 위해 다음을 사용합니다.

find . -maxdepth 1 -type f ! -name sums.sha1 -printf '%P\0' |
  xargs -r0 shasum -- > sums.sha1

대신에.

--시작하는 파일 이름 문제를 피하는 것입니다 -. 그러나라는 파일에는 도움이되지 않습니다 -. -print0대신에 사용했다면 파일 -printf '%P\0'이 필요 --없고 -파일에 문제가 없었을 것 입니다.


당신의 해결책은 내가 결국 사용한 것입니다. 특히 후속 실행이 체크섬 파일을 다시 해시하지 않고 디렉토리를 팽창시키지 않는 것이 좋습니다. 또한 내 스크립트 basename에서 주어진 전체 경로에서 sums.sha1 파일 이름을 가져 왔습니다 (질문에는 포함되지 않았지만 다른 사람들에게 도움이 될 수 있음).
user121391 2016 년

7

을 사용하고 있기 때문에 -maxdepth 1재귀를 원하지 않는다고 가정합니다. 그렇다면 쉘에서 대신 수행하십시오.

for f in ~/test/*; do
    shasum -- "$f"
done > sums.sha1

디렉토리를 건너 뛰려면 다음을 수행하십시오.

for f in ~/test/*; do
    [ ! -d "$f" ] && shasum -- "$f"
done > sums.sha1

재귀가 필요하고을 사용하는 bash경우 다음을 수행하십시오.

shopt -s globstar
for f in ~/test/**; do
    [ ! -d "$f" ] && shasum -- "$f"
done > sums.sha1

이러한 모든 접근 방식에는 공백, 줄 바꿈 또는 기타가 포함 된 파일 이름을 포함하여 임의의 파일 이름을 사용할 수 있다는 이점이 있습니다.


이것은 OP가 파일 이름에 줄 바꿈이있는 모든 문제를 해결한다고 언급한다고 생각합니다. 반면에 sums.sha1(이전 실행에서) 이미 있으면 솔루션에 통합됩니다.
Anthon 2016 년

죄송합니다. 이전에 명확히하지 않았습니다. maxdepth는이 예제에서만 사용되었으며 현재 깊이 1 만 필요하지만 사용자 / 스크립트가 값을 제공 할 수있는 기능을 사용합니다.
user121391

@ user121391은 재귀 접근법에 대한 업데이트 된 답변을 참조하십시오.
terdon

또한 파이프, 장치 ... (및 심볼릭 링크)와 같은 다른 유형의 비정규 파일을 체크섬하려고 시도합니다.
Stéphane Chazelas

개인적으로 님을 사용 sh하고 있지만 감사합니다 . 다른 사람에게 도움이 될 수 있습니다.
user121391 2016 년

4

zsh:

shasum -- *(D.) > sums.sha1

경로 재 지정이 수행되기 전에 글로브가 확장되므로 sums.sha1처음에없는 경우 포함되지 않습니다.

D도트 파일 (숨겨진 파일)을 포함하는 find것입니다. .와 같은 일반 파일 만 선택하는 것 -type f입니다.

sums.sha1어쨌든 그것이 처음에 있었던 경우 를 제외하려면 :

setopt extendedglob # best in ~/.zshrc
shasum -- ^sums.sha1(D.) > sums.sha1

이것들은 하나의 shasum 명령을 실행 하므로 목록이 너무 크면 "Arg list too long"오류가 표시 될 수 있습니다. 이를 해결하려면 다음을 수행하십시오.

autoload zargs
zargs -e/ -- *(D.) / shasum > sums.sha1

라는 파일의 잠재적 인 문제를 피하기 위해 ./*대신 사용 하는 것이 좋습니다 .*-


쉘 유형으로 질문을 편집했지만 얼마 전에 zsh로 전환하고 싶다는 답변이
나옵니다

1

다른 답변에서 이미 언급했듯이 문제는 sums.sha1파이프 라인을 실행하기 전에 셸이 파일을 열고 만듭니다 . 많은 배포판 패키지의 sponge일부인 프로그램 을 사용할 수 있습니다 moreutils. 셸 리디렉션과 달리 sponge파일을 열기 전에 모든 것을받을 때까지 기다립니다. 일반적으로 동일한 파이프 라인에서 읽은 파일을 쓰려고 할 때 사용됩니다.

귀하의 경우 다음과 같이 사용됩니다 :

$ find -maxdepth 1 -type f -printf '%P\n' |xargs shasum |sponge sums.sha1
$ cat sums.sha1
31836aeaab22dc49555a97edb4c753881432e01d  B
7d157d7c000ae27db146575c08ce30df893d3a64  A

0

find / xargs 등의 대안으로 sha1deep을 원할 수 있습니다. 그것은 아마도 다른 패키지에있을 것입니다-내 상자에는 md5deep 패키지가 있습니다.

다른 사람들이 말했듯이 sums.sha1은 찾기가 시작되기 전에 쉘에 의해 생성됩니다. 와 트릭 ! -name sums.sha1에는 find의지로 작동합니다

find -maxdepth 1 -type f -printf '%P\n' | xargs shasum | grep -v ' sums\.sha1$' > sums.sha1
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.