찾기 결과를 변수에 저장한 다음 cp에 전달하시겠습니까?

찾기 결과를 변수에 저장한 다음 cp에 전달하시겠습니까?

경과 시간을 기준으로 파일 세트를 처리해야 합니다(원격 디렉토리에 새 파일이 추가되는 시기를 제어할 수 없기 때문입니다).

파일 세트에 대해 여러 작업을 수행해야 하므로 find결과를 변수에 저장한 다음(해당되는 후보가 변경되지 않도록 할 수 있음) find각 작업에 대해 동일한 목록을 사용했습니다(별도의 작업을 수행할 필요 없음 ). 다시 할).

다음은 내가 시도하는 것의 간단한 버전입니다.

FILELIST=$(ssh ${SSHUSER}@${SSHHOST} "cd ${REMOTEPATH}; find -amin +${TIME} -type f,d -print")

if [[ ${#FILELIST} -lt 4 ]]; then
  echo "No files" >> ${LOGFILE}
  exit 1
fi

echo -en "Copying remote files to remote backup\n" >> ${LOGFILE}
ssh ${SSHUSER}@${SSHHOST} "cd ${REMOTEPATH}; cp -Rpv '${FILELIST}' ${REMOTEBACKUPPATH}" >> ${LOGFILE}

이것은 확실히 내가 cp: missing destination file operand after ''이해하는 바를 제공합니다. cp내가 원하는 방식으로 파일 목록의 형식을 지정하는 방법을 모르겠습니다 .

나는 문서/SE 게시물을 읽으면서 한동안 이 작업을 해왔지만 이해할 수 없습니다. 내가 무엇을 잘못하고 있는지 알게 되면 cp그 지식을 에 적용할 수 있기 를 바랍니다 rsync.

아직 명확하지 않다면 저는 bash 스크립팅의 세계를 처음 접했습니다. :)

미리 감사드립니다.

답변1

bash이 문제를 해결하는 데 가장 적합한 쉘은 아닙니다. 대신에 제안하겠습니다 ( 일부 매개변수 확장을 인용하지 않고 이미 구문을 사용하고 zsh있습니다 ).zsh

filelist=(
  ${(0)"$(
    ssh $SSHUSER@$SSHHOST "
      cd -- ${(qq)REMOTEPATH} &&
        find . -amin +${TIME} -type f,d -prune -print0"
  )"}
)

if (( $#filelist < 4 )); then
  print No files >> $LOGFILE
else
  print "Copying remote files to remote backup" >> $LOGFILE
  print -rNC1 -- $filelist | ssh $SSHUSER@$SSHHOST "
    cd -- ${(qq)REMOTEPATH} && xargs -r0 cp -Rpvt ${(qq)REMOTEBACKUPPATH}"
fi

( $SSHHOST이것이 GNU 시스템이라고 가정하고(당신은 이미 일부 GNUism을 사용하고 있습니다. 예를 들어 파일이 , f,d에 전달되지 않습니다 ) 로그인 쉘은 Bourne과 같은 것입니다.findcp -v$SSHUSER

어쨌든 이 전체 디렉토리를 복사하므로 그 안에 더 많은 파일을 찾을 필요가 없기 때문에 이를 명령 -prune에 추가 했습니다 . find이러한 디렉터리의 내용을 읽으면 마지막 액세스 시간도 업데이트됩니다.

그럼에도 불구하고 디렉터리의 파일을 읽어도 디렉터리의 액세스 시간은 업데이트되지 않습니다. 디렉토리의 액세스 시간은 디렉토리에서 ls/ 또는 쉘 전역 변수를 사용할 때와 마찬가지로 디렉토리 자체의 내용을 읽을 때 업데이트됩니다 find(요즘 액세스 시간이 항상 철저하게 유지되는 것은 아닙니다). 그래서 정확히 무엇을 하고 싶은지 명확하지 않습니다.

위에서는 다음을 사용합니다.

  • filelist=( values )정의하다대량으로filelist=value변수 (스칼라대신 변수).
  • ${(0)"$(cmd)"}cmdNUL에서 출력을 분할합니다. NUL은 파일 경로에 허용되지 않는 유일한 문자이므로 NUL로 구분된 목록을 사용하는 것은 파일 경로 목록을 전달하는 안전한 방법입니다.
  • cd -- ${(qq)REMOTEPATH}, 로 시작하는 값 (자체는 아니지만 / 일부 셸에서는 )과 인용된 값 (여기서는 기본 셸에 의해 확장됨)을 --방지하기 위해 ( ,$REMOTEPATH---4+3$REMOTEPATHqq유일한 안전한 방법$REMOTEPATH) 원격 셸의 경우(Bourne과 유사하다고 가정하고 로그인 셸이 csh/fish/rc...인 경우 일부 값에서는 작동하지 않습니다 $SSHUSER.)
  • &&성공할 경우에만 다음 명령이 실행되도록 보장합니다 . cd그렇지 않으면 잘못된 디렉터리에서 실행하게 됩니다.
  • -print0:NUL로 구분된 파일 경로를 인쇄합니다(위 참조).
  • 그러면 일치하는 파일의 수가 $#filelist포함됩니다(원래 코드의 4개와 비교했는데 이유는 확실하지 않습니다).
  • 그런 다음 해당 목록을 원격 호스트로 다시 보내야 합니다. 이를 원격 셸용으로 전송된 셸 코드의 인수로 전달하는 대신(다양한 문제와 제한 사항이 발생함) stdin에 print -NNUL로 구분하여(with) 전달하며 ssh이는 거기에 상속됩니다 xargs.
  • xargs목록을 읽고 이를 인수 cp -t target( -t또한 GNU 확장)로 변환합니다. 매개변수 크기 제한을 피하기 위해 필요한 만큼 xargs많은 를 실행합니다 .cp

관련 정보