디렉토리에서 마지막 N 파일을 얻는 방법?


15

디렉토리에 파일 이름별로 정렬 된 많은 파일이 있습니다. 최종 N (예 : N = 4) 파일을 내 홈 디렉토리에 복사하고 싶습니다. 어떻게해야합니까?

cp ./<the final 4 files> ~/


1
아래의 모든 답변에서 범위를 사용하는 명령 앞에 "LC_ALL = ..."을 추가하여 해당 범위가 올바른 로케일을 사용하도록 할 수 있습니다 (로케일이 변경 될 수 있으며 문자 순서가 변경 될 수 있음) 예를 들어, aabBcC .... zZ. 다른 변형이 존재합니다 (강조 문자 및 훨씬 더 이국적인 순서). 일반적인 선택은 다음과 같습니다.LC_ALL=C
Olivier Dulac

답변:


23

이것은 bash / ksh93 / zsh 배열로 쉽게 수행 할 수 있습니다.

a=(*)
cp -- "${a[@]: -4}" ~/

공백, 탭, 줄 바꿈 또는 기타 어려운 문자가 포함되어 있더라도 숨겨지지 않은 모든 파일 이름에서 작동합니다. bash ).

작동 원리

  • a=(*)

    a모든 파일 이름으로 배열 을 만듭니다 . bash가 리턴 한 파일 이름은 알파벳순으로 정렬됩니다. (이것이 "파일 이름순"으로 의미하는 것으로 가정합니다 . )

  • ${a[@]: -4}

    배열의 마지막 4 개 요소를 반환합니다 a(배열에 4 개 이상의 요소가 포함 된 경우 bash).

  • cp -- "${a[@]: -4}" ~/

    마지막 네 파일 이름이 홈 디렉토리로 복사됩니다.

동시에 복사하고 이름을 바꾸려면

이렇게하면 마지막 네 파일이 홈 디렉토리에만 복사되고 동시에 a_복사 된 파일 이름 앞에 문자열 이 추가 됩니다.

a=(*)
for fname in "${a[@]: -4}"; do cp -- "$fname" ~/a_"$fname"; done

다른 디렉토리에서 복사하고 이름을 바꿉니다.

우리가 사용하는 경우 a=(./some_dir/*)대신 a=(*), 우리는 디렉토리의 문제는 파일 이름에 부착되어 있습니다. 한 가지 해결책은 다음과 같습니다.

a=(./some_dir/*) 
for f in "${a[@]: -4}"; do cp "$f"  ~/a_"${f##*/}"; done

또 다른 해결책은 서브 쉘과 서브 쉘 cd의 디렉토리 를 사용하는 것입니다 .

(cd ./some_dir && a=(*) && for f in "${a[@]: -4}"; do cp -- "$f" ~/a_"$f"; done) 

서브 쉘이 완료되면 쉘은 원래 디렉토리로 우리를 리턴합니다.

순서가 일관성이 있는지 확인

질문은 "파일 이름으로 정렬 된"파일을 요청합니다. Olivier Dulac의 의견에 따르면, 그 순서는 로케일마다 다릅니다. 머신 설정과 관계없이 고정 된 결과를 가져야하는 경우 배열 a이 정의 될 때 로케일을 명시 적으로 지정하는 것이 가장 좋습니다 . 예를 들면 다음과 같습니다.

LC_ALL=C a=(*)

locale명령 을 실행하여 현재있는 로케일을 찾을 수 있습니다 .


9

사용하는 경우 원하는 파일을 선택하는 소위 glob 한정자 목록을 zsh괄호 ()로 묶을 수 있습니다. 귀하의 경우에는

cp *(On[1,4]) ~/

여기에서 On파일 이름을 알파벳순으로 역순으로 정렬하고[1,4] 처음 4 개만 사용합니다.

로 일반 파일 (디렉토리, 파이프 등 제외) 만 선택하고 이름이 올바르게 시작하는 파일을 처리하기 위해 명령에 .추가 --하여 이를 더욱 강력하게 만들 수 있습니다 .cp-

cp -- *(.On[1,4]) ~

D숨겨진 파일 (도트 파일)도 고려 하려면 규정자를 추가하십시오 .

cp -- *(D.On[1,4]) ~

2
또는 : *([-4,-1]).
Stéphane Chazelas

2
@ StéphaneChazelas 예에 알파벳 순으로 정렬하는 것이 미래의 독자 명확히 할 수 있습니다 정상 방향 것은 ( on필요 이것을 지정하지 않는, 그래서) 기본 동작이며, -바닥에서 숫자 카운트 파일 이름 앞에.
jimmij

7

다음은 매우 간단한 bash 명령을 사용하는 솔루션입니다.

find . -maxdepth 1 -type f | sort | tail -n 4 | while read -r file; do cp "$file" ~/; done

설명:

find . -maxdepth 1 -type f

현재 디렉토리에서 모든 파일을 찾습니다.

sort

알파벳순으로 정렬합니다.

tail -n 4

마지막 4 줄만 표시하십시오.

while read -r file; do cp "$file" ~/; done

복사 명령을 수행하는 각 줄을 반복합니다.


6

쉘 정렬이 합리적이라면 다음과 같이하면됩니다.

set -- /path/to/source/dir/*
[ "$#" -le 4 ] || shift "$(($#-4))"
cp "$@" /path/to/target/dir

이것은 bash제공되는 특정 어레이 솔루션 과 매우 유사 하지만 POSIX 호환 쉘로 이식 가능해야합니다. 두 가지 방법에 대한 참고 사항 :

  1. cp논쟁 을 이끌 cp --거나 .점 하나 또는 /각 이름의 머리 중 하나를 얻는 것이 중요합니다 . 이를 수행하지 않으면 옵션으로 해석되어 작업이 실패하거나 의도하지 않은 결과를 초래할 수있는 첫 번째 인수 -에서 선행 대시가 발생할 위험이 있습니다 cp.

    • 현재 디렉토리를 소스 디렉토리로 사용하더라도 ... set -- ./*또는 array=(./*).
  2. 두 가지 방법을 모두 사용하여 제거하려고 시도하는 것처럼 최소한 arg 배열에 많은 항목이 있는지 확인하는 것이 중요합니다. 여기서는 수학 확장으로 수행합니다. 는 shift적어도 4 개 인수 배열에 항목이있는 경우에만 발생합니다 - 단지 변화 떨어진 후 4의 흑자를 만들 그 첫번째 인수가 ..

    • 따라서 어떤 set 1 2 3 4 5경우에는 1멀리 이동 하지만 어떤 set 1 2 3경우에는 아무것도 이동하지 않습니다.
    • 예를 들어 : a=(1 2 3); echo "${a[@]: -4}"빈 줄을 인쇄합니다.

한 디렉토리에서 다른 디렉토리로 복사하는 경우 다음을 사용할 수 있습니다 pax.

set -- /path/to/source/dir/*
[ "$#" -le 4 ] || shift "$(($#-4))"
pax -rws '|.*/|new_prefix|' "$@" /path/to/target/dir

... sed모든 파일 이름을 복사 할 때 스타일 대체를 적용 합니다.


4

파일 만 있고 파일 이름에 공백이나 줄 바꿈 (및 수정하지 않은 $IFS) 또는 glob 문자 (또는 일부 구현이있는 인쇄 할 수없는 문자 ls)가 포함되어 있지 않은 .경우 다음 과 같이 시작할 수 없습니다 :

cp -- $(ls | tail -n 4) ~/

이것을 명령 대체라고하며 정말 편리합니다. tldp.org/LDP/abs/html/commandsub.html#CSPARENS
iyrin

감사! 효과가있다. a_네 파일 모두에 접두사를 빠르게 추가 할 수 있습니까? 나는 시도 echo "a_$(ls | tail -n 4)"했지만 첫 번째 파일 앞에 추가합니다.
Sibbs Gambling

@SibbsGambling 내 접근 방식은 적합하지 않지만 John1024의 답변은 쉽게 적용 할 수 있습니다.
Hauke ​​Laging

5
일반적으로 구문 분석 ls출력은 공백뿐만 아니라 탭, 줄 바꿈 또는 기타 유효하지만 "어려운"문자를 ​​포함하는 파일 이름에서 크게 실패하기 때문에 잘못된 형식으로 간주됩니다.
HBruijn

2
@HaukeLaging 현재 문제가 아니더라도 (내 디렉토리에 "복잡한"화염 이름이 없기 때문에) 2 년이
지나고

1

이것은 루프 코드가없는 간단한 bash 솔루션입니다. 현재 디렉토리에서 대상으로 마지막 4 개의 파일을 복사하십시오.

$ find . -maxdepth 1 -type f |tail -n -4|xargs cp -t "$destdir"

1
find원하는 순서대로 파일 을 제공 하는지 어떻게 확인 합니까? 이름에 공백 문자 (줄 바꾸기 포함)가 포함 된 파일이 올바르게 처리되도록하려면 어떻게해야합니까?
Kusalananda
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.