원격 디렉터리에서 가장 최근에 수정된 파일을 SCP로 삭제

원격 디렉터리에서 가장 최근에 수정된 파일을 SCP로 삭제

원격 호스트의 디렉토리에서 가장 최근에 수정된 파일을 SCP로 지정하는 간단한 명령이 있습니까? 로컬에서 원격으로 이를 수행하는 방법을 알아낼 수 있습니다. 다음과 같은 것입니다. scp ``ls -Art | tail -n 1\`` usr@remote:/var/log/yeet 동일한 작업을 원격에서 로컬로 어떻게 수행할 수 있습니까? (그래서 yeet에서 가장 최근에 수정된 파일을 가져와서 로컬 호스트에 복사하세요)

답변1

여기에는 몇 가지 문제가 있습니다.

파싱ls

우선 당신은파싱하면 안 된다ls. 당신의 ls -Art | tail -n 1결함은 확실하게 고칠 수 없습니다. 신뢰할 수 있는 표준 대체 방법은 find널 종료 라인을 사용하거나 사용하는 것입니다.

또한 가장 최근에 수정된 파일(디렉토리 아님)이 현재 디렉터리(하위 디렉터리가 아님)에 직접 필요하다고 가정합니다.

Null로 끝나는 목록 형식의 입력 항목을 구문 분석하는 기능은 일반적으로 POSIX에서 필요하지 않습니다. 도구에 옵션이 충분히 풍부하다면 다음을 위한 강력한 대체 도구입니다 ls -Art | tail -n 1.

find . -maxdepth 1 -type f -printf '%T@ %p\0' |
   sort -zrn |
   head -zn 1 |
   cut -z -d " " -f 2-

결과는 null로 끝나는 파일 이름으로 생성됩니다. 이것으로 뭔가를 하려면 파이프로 연결해야 합니다 xargs -0 …. 예:

… | xargs -0r cp -t "/target/dir/" --

또는 ( cp지원하지 않는 경우 -t):

… | xargs -0r -I {} cp -- {} "/target/dir/"

--이러한 명령에는 옵션 구문 분석을 중지 하는 등 POSIX에 필요하지 않은(따라서 이식할 수 없는) 것들이 많이 있습니다. cp예를 들어 파일이 -R복사되는 대신 재귀를 트리거하지 않습니다. find . …시작 부분을 벗어나는 파일 이름은 .확실하므로 --생략해도 안전합니다. 나는 단지 cp. 또 다른 좋은 방법은 경로를 인용하는 것입니다. 리터럴은 /target/dir/따옴표 없이 작동하지만 이 예제를 특정 대상 경로로 바꾼 후에는 따옴표가 필요할 수 있으므로 어쨌든 사용하겠습니다.

(로컬에서 원격으로) 경우에는 scp대신에 를 사용합니다 cp. 인수를 구문 분석하는 동안 고유한 문제가 있을 수 있습니다.

POSIX를 준수하지만 제대로 수행되지 않는 명령은 다음과 같습니다.

find . ! -name . -prune -type f -exec sh -c '
   [ "$(find . ! -name . -prune -type f -newer "$1" -exec printf a \; |
   wc -c)" -eq 0 ]' sh {} \; -print

그것은 다음의 접근 방식을 채택합니다.이건 또 다른 대답이야(POSIX가 아닌)을 대체합니다 -maxdepth 1. sh안정적으로 생성됩니다 .find … -exec …두 개의 절을 중첩. 외부는 find모든 파일을 조사하여 하나씩 내부에 제공합니다 find. 내부는 find지정된 파일보다 최신인 모든 파일을 찾아 a모든 최신 파일에 대해 단일 문자( )를 인쇄합니다. wc -c이 문자를 계산합니다. 아무것도 없으면 해당 파일이 가장 최근에 수정되었음을 의미합니다. 그래야만 외부가 find인쇄합니다.

find외부가 두 개 이상의 파일을 인쇄할 수 있는 몇 가지 시나리오가 있습니다 .

  • 동일한 "최신" mtime을 가진 파일이 두 개 이상 있습니다.
  • 명령이 실행되는 동안 디렉터리의 파일이 수정됩니다.
  • 내부는 find일부 파일을 상태화할 수 없습니다.

이러한 이유로 -quit외부의 최종 동작이 find유용할 것입니다(내부에도 유용 find하지만 다른 이유가 있습니다). 불행히도 -quitPOSIX는 아닙니다.

나는 -print( -print0POSIX가 아님)을 사용했지만 출력을 다른 명령으로 파이프할 필요가 없기 때문에 여전히 비표준 파일 이름은 문제가 되지 않습니다. -exec가능한 모든 파일 이름을 올바르게 처리하는 데 사용하십시오 . 예를 들어 다음을 사용하는 대신 -print:

-exec yet_another_command {} \;

이제 구문 분석 없이 로컬 디렉터리에서 가장 최근에 수정된 파일을 찾는 방법을 알았습니다 ls.

원격 시스템에서 파일 찾기

어떤 접근 방식을 선택하든(결함 포함 ls … | tail …) 원격 디렉터리에서 원하는 파일을 찾으려면 원격 시스템에서 명령을 실행해야 합니다(또는 그렇지 않으면 나중에 이 예외에 대해 설명하겠습니다).

가장 확실한 접근 방식은 ssh원격 시스템에 접속하는 것입니다. 새 컨텍스트에서 원격 시스템은 로컬이고 로컬 컴퓨터는 원격입니다. (여기서는 위의 POSIX 호환 명령을 예로 사용하고 있지만 find … | sort -z … | head -z … | cut -z … | xargs -0 …원격 시스템이 필요한 모든 옵션을 지원하는 경우에만 첫 번째 명령을 사용할 수 있습니다.)

ssh usr@remote
# now on the remote system
cd "/source/dir/" &&
find . ! -name . -prune -type f -exec sh -c '
   [ "$(find . ! -name . -prune -type f -newer "$1" -exec printf a \; |
   wc -c)" -eq 0 ]' sh {} \; -exec scp {} usr@local:"/target/dir/" \;

cd피하고 사용 하려면 로 대체해야 하는 -s가 find /source/dir …더 많이 있습니다 . 을 사용하면 훨씬 더 쉽습니다 ../source/dircd

원격 시스템에서 SSH를 통해 로컬 시스템을 사용할 수 있어야 합니다. 도중에 NAT가 있는 경우 다음과 같이 원격 포트 전달을 사용하여 이를 우회할 수 있습니다.

ssh -R 12322:127.0.0.1:22 usr@remote
# now on the remote system the same cd + find as above
# only the scp part is different 
… -exec scp -P 12322 {} [email protected]:"/target/dir/" \;

원격 포트가 12322로컬로 연결 되고 sshd원격 시스템의 모든 사용자가 이를 오용하려고 시도할 수 있습니다. 또 다른 문제: 원격 시스템이 처음부터 포트 전달을 허용하지 않도록 구성되었을 수 있습니다.

로컬 시스템에서 단일 명령을 호출할 수도 있습니다. 이 경우 적절한 인용이 필요하며 훨씬 더 번거로워집니다.

ssh usr@remote '
   cd "/source/dir/" &&
   find . ! -name . -prune -type f -exec sh -c '"'"'
      [ "$(find . ! -name . -prune -type f -newer "$1" -exec printf a \; |
      wc -c)" -eq 0 ]'"'"' sh {} \; -exec scp {} usr@local:"/target/dir/" \;
   '

그래도 리모컨이 scp비밀번호를 물어야 한다면 문제가 발생할 것으로 예상됩니다. 이러한 이유로 또는 로컬을 실행/접근할 수 없는 경우 sshd또 다른 접근 방식이 필요할 수 있습니다.

이 로컬 명령은 원격 시스템에서 얻은 원하는 파일 이름을 인쇄합니다.

ssh usr@remote '
   cd "/source/dir/" &&
   find . ! -name . -prune -type f -exec sh -c '"'"'
      [ "$(find . ! -name . -prune -type f -newer "$1" -exec printf a \; |
      wc -c)" -eq 0 ]'"'"' sh {} \; -print
   '

당신은 그것을 사용할 수 있습니다현지의xargs및 와 같은 도구입니다 scp. 결과를 구문 분석하는 것은 -print구문 분석보다 약간 더 나을 뿐입니다 ls. 원하는 파일 이름을 null로 끝나는 문자열로 얻는 대신 -print0(POSIX가 아닌 경우 사용 불가능할 수 있음) 또는 (작동해야 함)을 사용 하십시오. 이제 로컬 측에서 이를 사용하여 무엇을 할 것인지는 귀하에게 달려 있습니다. 이는 POSIX 호환 원격 명령이 필요하지만 로컬 시스템의 도구에 옵션이 풍부한 경우에 유용합니다.-exec printf "%s\0" {} \;-print

주목할만한 예외:sshfs

sshfsusr@remote:"/source/dir/"으로 마운트할 수 있습니다 /local/path/. 보다내 이 대답, 모든 세부 사항을 다루기 위해 반복하지 않겠습니다. 귀하의 경우 풍부한(POSIX에 국한되지 않음) 도구를 사용하는 (로컬) 절차는 다음과 같습니다.

sshfs usr@remote:"/source/dir/" "/local/path/"
find "/local/path/" -maxdepth 1 -type f -printf '%T@ %p\0' |
   sort -zrn |
   head -zn 1 |
   cut -z -d " " -f 2- |
   xargs -0r cp -t "/target/dir/" --
fusermount -u "/local/path/"

이것은 훌륭합니다. 당신이 하는 모든 일은 당신이 하는 일현지의도구. sshfs원격 측의 도구를 사용할 수 있고 사용 가능한 옵션이 더 이상 중요하지 않은 경우 . 외부에서 로컬 시스템에 접근할 수 있는지 여부도 중요하지 않습니다. 방법은 동일합니다. 원격에서 로컬로, 로컬에서 원격으로 상관없습니다.

관련 정보