[linux] 최신 파일 일치 패턴을 찾는 Bash 기능

Bash에서는 특정 패턴과 일치하는 최신 파일의 파일 이름을 반환하는 함수를 만들고 싶습니다. 예를 들어 다음과 같은 파일 디렉토리가 있습니다.

Directory/
   a1.1_5_1
   a1.2_1_4
   b2.1_0
   b2.2_3_4
   b2.3_2_0

‘b2’로 시작하는 최신 파일을 원합니다. bash에서 어떻게해야합니까? 내 ~/.bash_profile스크립트에 이것을 가지고 있어야합니다 .



답변

ls명령에는 -t시간별로 정렬 할 매개 변수 가 있습니다. 그런 다음을 사용하여 첫 번째 (최신)를 가져올 수 있습니다 head -1.

ls -t b2* | head -1

그러나주의하십시오 : 왜 ls의 출력을 파싱해서는 안됩니까?

내 개인적인 의견 : 파싱 ls은 파일 이름에 공백이나 줄 바꿈과 같은 재미있는 문자가 포함될 수있는 경우에만 위험합니다. 파일 이름에 재미있는 문자가 포함되어 있지 않다고 보장하면 구문 분석 ls이 매우 안전합니다.

많은 다른 상황에서 많은 시스템에서 많은 사람들이 실행할 스크립트를 개발하고 있다면 구문 분석하지 않는 것이 좋습니다 ls.

“올바르게”하는 방법은 다음과 같습니다 . 디렉토리에서 최신 (최신, 초기, 가장 오래된) 파일을 어떻게 찾을 수 있습니까?

unset -v latest
for file in "$dir"/*; do
  [[ $file -nt $latest ]] && latest=$file
done


답변

의 조합 findls잘 작동

  • 줄 바꿈이없는 파일 이름
  • 매우 많은 양의 파일
  • 그리 길지 않은 파일 이름

해결책:

find . -name "my-pattern" -print0 |
    xargs -r -0 ls -1 -t |
    head -1

그것을 분해하자 :

다음과 find같이 흥미로운 파일을 모두 일치시킬 수 있습니다.

find . -name "my-pattern" ...

그런 다음 -print0모든 파일 이름을 다음 ls과 같이 안전하게 전달할 수 있습니다 .

find . -name "my-pattern" -print0 | xargs -r -0 ls -1 -t

추가 find검색 매개 변수 및 패턴을 여기에 추가 할 수 있습니다

find . -name "my-pattern" ... -print0 | xargs -r -0 ls -1 -t

ls -t수정 시간 (가장 먼저)별로 파일을 정렬하여 한 줄에 하나씩 인쇄합니다. -c생성 시간을 기준으로 정렬하는 데 사용할 수 있습니다 . 참고 : 이것은 줄 바꿈이 포함 된 파일 이름으로 중단됩니다.

마지막으로 head -1정렬 목록에서 첫 번째 파일을 가져옵니다.

참고 : xargs 인수 목록의 크기에 시스템 제한을 사용하십시오. 이 크기를 초과하면 여러 번 xargs호출 ls됩니다. 이것은 정렬과 아마도 최종 출력을 깨뜨릴 것입니다. 운영

xargs  --show-limits

시스템의 한계를 확인하십시오.

참고 2 :find . -maxdepth 1 -name "my-pattern" -print0 하위 폴더를 통해 파일을 검색하지 않으려면 사용 하십시오.

참고 3 : @ starfry-ar에 의해 지적 된 바와 같이에 -r대해 일치하는 파일이없는 경우에 xargs대한 호출을 막는 ls -1 -tfind입니다. 제안 해 주셔서 감사합니다.


답변

이것은 필요한 Bash 함수의 가능한 구현입니다.

# Print the newest file, if any, matching the given pattern
# Example usage:
#   newest_matching_file 'b2*'
# WARNING: Files whose names begin with a dot will not be checked
function newest_matching_file
{
    # Use ${1-} instead of $1 in case 'nounset' is set
    local -r glob_pattern=${1-}

    if (( $# != 1 )) ; then
        echo 'usage: newest_matching_file GLOB_PATTERN' >&2
        return 1
    fi

    # To avoid printing garbage if no files match the pattern, set
    # 'nullglob' if necessary
    local -i need_to_unset_nullglob=0
    if [[ ":$BASHOPTS:" != *:nullglob:* ]] ; then
        shopt -s nullglob
        need_to_unset_nullglob=1
    fi

    newest_file=
    for file in $glob_pattern ; do
        [[ -z $newest_file || $file -nt $newest_file ]] \
            && newest_file=$file
    done

    # To avoid unexpected behaviour elsewhere, unset nullglob if it was
    # set by this function
    (( need_to_unset_nullglob )) && shopt -u nullglob

    # Use printf instead of echo in case the file name begins with '-'
    [[ -n $newest_file ]] && printf '%s\n' "$newest_file"

    return 0
}

Bash 내장만을 사용하며 이름에 개행 문자 또는 기타 특이한 문자가 포함 된 파일을 처리해야합니다.


답변

비정상적인 파일 이름 (예 : 유효한 \n문자를 포함하는 파일) 은 이런 종류의 구문 분석으로 혼란을 초래할 수 있습니다.

perl -le '@sorted = map {$_->[0]}
                    sort {$a->[1] <=> $b->[1]}
                    map {[$_, -M $_]}
                    @ARGV;
          print $sorted[0]
' b2*

그것은 그곳에서 사용 된 슈바르츠 식 변환 입니다.


답변

stat파일 글로브와 함께 사용할 수 있으며 파일 시간이 앞면에 추가 된 데코 레이트-소트-장식되지 않습니다 :

$ stat -f "%m%t%N" b2* | sort -rn | head -1 | cut -f2-


답변

find ... xargs ... head ...위 의 솔루션 을 원 하지만 기능 양식을 사용하기 쉬운 사람들을위한 다크 매직 기능 주문은 다음과 같이 생각할 필요가 없습니다.

#define the function
find_newest_file_matching_pattern_under_directory(){
    echo $(find $1 -name $2 -print0 | xargs -0 ls -1 -t | head -1)
}

#setup:
#mkdir /tmp/files_to_move
#cd /tmp/files_to_move
#touch file1.txt
#touch file2.txt

#invoke the function:
newest_file=$( find_newest_file_matching_pattern_under_directory /tmp/files_to_move/ bc* )
echo $newest_file

인쇄물:

file2.txt

어느 것이 :

주어진 디렉토리에서 파일의 가장 오래된 수정 된 타임 스탬프를 가진 파일 이름이 주어진 패턴과 일치합니다.


답변

find 명령을 사용하십시오.

Bash 4.2 이상을 사용한다고 가정하면 -printf '%T+ %p\n'파일 타임 스탬프 값에 사용하십시오.

find $DIR -type f -printf '%T+ %p\n' | sort -r | head -n 1 | cut -d' ' -f2

예:

find ~/Downloads -type f -printf '%T+ %p\n' | sort -r | head -n 1 | cut -d' ' -f2

보다 유용한 스크립트를 보려면 https://github.com/l3x/helpers에서 최신 스크립트 찾기를 참조 하십시오.