최신 파일 5개를 로컬 디렉터리에 안전하게 복사하는 방법

최신 파일 5개를 로컬 디렉터리에 안전하게 복사하는 방법

이 코드 줄이 있습니다

scp -r ${server}:${server_dir}/$(ssh ${server} "ls -t ${server_dir} | head -5") logs/ios

실행 시 5개 파일 중 최신 파일만 scp되며 출력은 다음과 같습니다.

iosTestOutput_20180831-175508-PDT.tgz                                                                100%  199KB  21.7MB/s   00:00
cp: iosTestOutput_20180831-155546-PDT.tgz: No such file or directory
cp: iosTestOutput_20180831-142509-PDT.tgz: No such file or directory
cp: iosTestOutput_20180831-124259-PDT.tgz: No such file or directory
cp: iosTestOutput_20180831-115001-PDT.tgz: No such file or directory

그러나 실제로 대상 디렉토리에 ssh를 연결하고 이러한 파일이 존재하는 것을 관찰했기 때문에 내가 뭘 잘못하고 있는지 잘 모르겠습니다.

답변1

첫 번째 파일에만 scp에 필요한 절대 경로가 있습니다.

${server}:${server_dir}/$(ssh ${server} "ls -t ${server_dir} | head -5")으로 평가될 것이다

${server}:${server_dir}/iosTestOutput_20180831-175508-PDT.tgz
iosTestOutput_20180831-155546-PDT.tgz
iosTestOutput_20180831-142509-PDT.tgz
...

명확성을 위해 공백 대신 개행 문자를 사용했습니다.

기본적으로 5개 파일 출력 각각에 대한 전체 경로의 내용을 사용하여 생성된 목록을 반복해야 합니다.https://unix.stackexchange.com/a/240424/162359좋은 시작이 될 수도 있습니다.

(테스트되지 않음, 대략적인 스케치임) 다음과 같습니다.

for bkp in $(ssh ${server} "find ${absolute_path_remote_dir} -type f -exec stat -c '%X %n' {} \; | sort -nr | awk 'NR==1,NR==5 {print $2}'")
do
scp -r ${bkp} logs/ios
done

rsync에는 원하는 것을 더욱 우아하게 달성하는 데 도움이 되는 옵션이 있을 수도 있습니다.

답변2

실행할 때:

scp -r ${server}:${server_dir}/$(ssh ${server} "ls -t ${server_dir} | head -5")

...일어나는 첫 번째 (중요한) 일은 로컬 쉘이 여기에서 명령 대체를 해석하기 시작한다는 것입니다.

$(ssh ${server} "ls -t ${server_dir} | head -5")

위의 명령 대체는 대부분 생각대로 작동합니다. 파일 이름에 공백이나 개행(또는 탭)이 있으면 바로 중단됩니다. 예를 들어 다음과 같은 5개의 최신 파일이 있을 수 있습니다.

  • temp file
  • a
  • b
  • c
  • d

귀하에게는 다음이 제공 됩니다 ssh ... ls -t | head -5:

a
b
c
d
temp file

...그러나 명령 대체는 출력에서 ​​줄 바꿈을 제거하고 다음 문자열을 반환합니다.

a b c d temp file

...이제 실제 원본 파일 이름과 구별할 수 없습니다.

이와 같은 파일 이름은 결코 접하지 못할 수도 있지만, 그 반대의 경우보다 안전하고 물리지 않는 것이 더 안전합니다.

따라서 파일 이름을 로컬 시스템으로 안전하게 검색한 다음 구체적으로 검색하는 것이 좋습니다.

server=server-name-here  ## replace with your values
server_dir=/tmp          ## replace with your values

files=($(ssh "$server" "zsh -c 'print -N -- ${server_dir}/*(om.[1,5])'" 2>/dev/null ) )
for f in ${files[1,5]}
do
  scp "${server}:${f}" logs/ios
done

가장 어려운 부분은 가장 최근에 수정된 5개 파일의 원격 목록을 검색하는 것입니다. 여기서는 ssh를 통해 서버에 연결하고 zsh를 호출하여 광범위한 글로빙 메커니즘을 사용하여 반환합니다.

  • ${server_dir}의 파일
  • om산화 시간별 로 정렬
  • .일반 파일( ) 입니다 .
  • 그리고 처음 5개는 다음과 같습니다.[1,5]

여기서는 zsh 내장 명령을 사용하여 printnull로 구분되고 null로 끝나는 결과 파일 목록을 반환합니다. null을 포함하는 이 문자열은 ssh를 통해 zsh로 다시 전달되며, 이는 문자열을 null로 분할하고 내용을 배열에 할당합니다 files.

그런 다음 처음 5개 요소(6번째 요소는 null이므로)만 가져오도록 주의하면서 배열을 반복하고 scp각 파일을 차례로 호출합니다.

원한다면 원격 파일 이름 문자열( ${server}:${file1} ${server}:${file2} ...)을 신중하게 작성하고 scp한 번만 호출할 수 있습니다. 한 가지 가능성은 다음과 같습니다.

scp ${server}:${(qq)^files[1,5]} logs/ios

...이것은 zsh가 배열의 처음 5개 요소에 문자열(실제 서버 이름으로 대체된 ${server}, 그 뒤에 콜론이 옴)을 추가하도록 지시하기 때문입니다. 배열의 모든 파일 이름이 참조됩니다.

답변3

hhoke1이 말했듯이 절대 경로가 누락되었습니다.

ls -t | head -5 | xargs readlink -f

이것은 scp에 대한 절대 경로를 제공해야 하지만 readlink파이프에서 입력을 읽을 수 없는 것 같아서 xargs.

관련 정보