디렉토리에서 최신 파일을 ‘꼬리’하는 방법 tail에서 디렉토리에 최신 파일을 어떻게 만들

tail에서 디렉토리에 최신 파일을 어떻게 만들 수 있습니까?



답변

마십시오 하지 LS의 출력을 구문 분석! ls의 출력을 파싱하는 것은 어렵고 신뢰할 수 없습니다 .

이 작업을 수행해야하는 경우 find를 사용하는 것이 좋습니다. 원래 나는 여기에 간단한 해결책을 제시하기위한 간단한 예를 가지고 있었지만이 대답은 다소 인기가있는 것처럼 보이기 때문에 복사 / 붙여 넣기 및 모든 입력과 함께 사용하기에 안전한 버전을 제공하기 위해 이것을 수정하기로 결정했습니다. 편안하게 앉아 있습니까? 현재 디렉토리의 최신 파일을 제공하는 oneliner로 시작하겠습니다.

tail -- "$(find . -maxdepth 1 -type f -printf '%T@.%p\0' | sort -znr -t. -k1,2 | while IFS= read -r -d '' -r record ; do printf '%s' "$record" | cut -d. -f3- ; break ; done)"

지금은 하나의 라이너가 아닌가? 다음은 다시 셸 함수로 사용되며 읽기 쉽도록 형식화되었습니다.

latest-file-in-directory () {
    find "${@:-.}" -maxdepth 1 -type f -printf '%T@.%p\0' | \
            sort -znr -t. -k1,2 | \
            while IFS= read -r -d '' -r record ; do
                    printf '%s' "$record" | cut -d. -f3-
                    break
            done
}

그리고 지금 oneliner으로 :

tail -- "$(latest-file-in-directory)"

다른 모든 방법이 실패하면 위의 기능을 포함시킬 수 .bashrc있고 한 가지 경고로 해결 된 문제를 고려할 수 있습니다. 당신이 일을 끝내기를 원한다면 더 이상 읽을 필요가 없습니다.

이것에 대한주의 사항은 하나 이상의 줄 바꿈으로 끝나는 파일 이름이 여전히 tail올바르게 전달되지 않는다는 것입니다. 이 문제를 해결하는 것은 복잡하며 이러한 악의적 인 파일 이름이 발견되면 상대적으로 위험한 파일 대신 “No such file”오류가 발생하는 비교적 안전한 동작이 발생하기에 충분하다고 생각합니다.

수분이 많은 세부 사항

궁금한 점은 이것이 작동하는 방식, 왜 안전한지, 왜 다른 방법이 그렇지 않은지에 대한 지루한 설명입니다.

위험, 윌 로빈슨

우선, 파일 경로를 구분하기에 안전한 유일한 바이트는 유닉스 시스템의 파일 경로에서 보편적으로 금지 된 유일한 바이트이기 때문에 null입니다. 파일 경로 목록을 처리 할 때는 null을 구분 기호로만 사용하고 한 파일에서 다른 파일 경로로 단일 파일 경로를 전달할 때 임의 바이트에서 질식하지 않는 방식으로 처리하는 것이 중요합니다. 파일 이름에 줄 바꿈이나 공백이 없다고 가정하여 실패하는 문제와 다른 문제를 해결하는 겉으로는 올바른 방법이 많이 있습니다. 어느 가정도 안전하지 않습니다.

오늘의 목적을위한 첫 번째 단계는 null로 구분 된 파일 목록을 찾을 수 없도록하는 것입니다. GNU와 같은 find지원 이있는 경우 매우 쉽습니다 -print0.

find . -print0

그러나이 목록에는 여전히 최신 정보가 나와 있지 않으므로 해당 정보를 포함시켜야합니다. -printf출력에 표시 할 데이터를 지정할 수있는 find 스위치 를 사용하도록 선택합니다 . 모든 버전의 find지원 -printf(표준이 아님)은 아니지만 GNU find는 지원합니다. -printf당신이 없는 자신을 발견 하면 -exec stat {} \;어느 시점 에 의존 해야 stat표준이 아니므 로 휴대 성의 모든 희망을 포기해야 합니다. 지금은 GNU 도구가 있다고 가정하겠습니다.

find . -printf '%T@.%p\0'

여기서 나는 %T@유닉스 시대가 시작된 이후의 마침표와 그 후의 분수를 나타내는 숫자가 뒤 따르는 수정 시간 인 printf 형식 을 묻습니다 . %pnull 바이트로 끝나기 전에이 다른 기간을 추가 한 다음 (파일의 전체 경로)를 추가합니다.

지금 나 한테있어

find . -maxdepth 1 \! -type d -printf '%T@.%p\0'

말할 것도없이 완료 될 수 있지만 하위 디렉토리의 내용을 나열 -maxdepth 1하지 못하게 하고 원하지 않는 디렉토리는 건너 뜁니다 . 지금까지 수정 시간 정보가있는 현재 디렉토리에 파일이 있으므로 수정 시간을 기준으로 정렬해야합니다.find\! -type dtail

올바른 순서로 가져 오기

기본적 sort으로 입력은 개행으로 구분 된 레코드 일 것으로 예상합니다. GNU를 가지고 있다면 스위치 sort를 사용하여 대신 널로 구분 된 레코드를 요구할 수 있습니다 -z.; 표준의 sort경우 해결책이 없습니다. 나는 처음 두 숫자 (초와 초의 분수)로만 정렬하고 실제 파일 이름으로 정렬하고 싶지 않으므로 sort두 가지를 말하고 싶습니다 . 먼저, .필드 구분 기호 (마침표 ( )를 고려해야 함 ) 둘째, 레코드 정렬 방법을 고려할 때 첫 번째 필드와 두 번째 필드 만 사용해야합니다.

| sort -znr -t. -k1,2

우선, 나는 가치를 함께 취하지 않는 세 가지 짧은 옵션을 묶습니다. -znr간결한 말입니다 -z -n -r). 그 후 -t .(공백은 선택 사항 임) sort필드 구분 문자를 알려주고 -k 1,2필드 번호를 지정합니다 : first 및 second ( sort0이 아닌 1부터 필드를 계산). 현재 디렉토리의 샘플 레코드는 다음과 같습니다.

1000000000.0000000000../some-file-name

즉 , 이 레코드를 주문할 때 sort먼저 확인해야 합니다. 이 옵션은 두 값이 모두 숫자이므로이 값을 비교할 때 숫자 비교를 사용하도록 지시 합니다. 숫자의 길이는 고정되어 있지만 해를 끼치 지 않으므로 중요하지 않을 수 있습니다.10000000000000000000-nsort

다른 스위치 sort-r“reverse”입니다. 기본적으로 숫자 정렬의 출력은 가장 낮은 숫자부터 시작 -r하여 가장 낮은 숫자와 가장 높은 숫자를 먼저 나열하도록 변경합니다. 이 숫자는 타임 스탬프가 높을수록 더 새로운 것을 의미하므로 목록의 시작 부분에 최신 레코드가 저장됩니다.

중요한 부분 만

파일 경로 목록이 나오면 sort이제 원하는 답을 찾을 수 있습니다. 남은 것은 다른 레코드를 삭제하고 타임 스탬프를 제거하는 방법을 찾는 것입니다. 불행하게도, 심지어 GNU는 head하고 tail그들이 널 (null)로 구분 된 입력을 작동 할 수 있도록 스위치를 허용하지 않습니다. 대신 나는 while 루프를 가난한 사람의 일종으로 사용합니다 head.

| while IFS= read -r -d '' record

먼저 IFS파일 목록에 단어 분할이 적용 되지 않도록 설정을 해제했습니다 . 다음으로 나는 read두 가지를 말한다 : 입력 ( -r) 에서 이스케이프 시퀀스를 해석하지 말고 입력은 널 바이트 ( -d)로 구분된다 ; 여기서 빈 문자열 ''은 “구분 기호 없음”을 일명 null로 구분하는 데 사용됩니다. 루프를 반복 할 record때마다 while단일 타임 스탬프와 단일 파일 이름을 갖도록 각 레코드를 변수로 읽어들 입니다. 참고 -dGNU 확장이다; 표준 만있는 read경우이 기술은 작동하지 않으며 약간의 의지가 있습니다.

우리는 알고 record변수가 모든 기간 문자로 구분이 세 부분을 가지고 있습니다. 은 Using cut유틸리티를 그들 중 일부를 추출하는 것이 가능하다.

printf '%s' "$record" | cut -d. -f3-

여기에서 전체 레코드가 printf파이프로 전달 됩니다 cut. bash 에서는 성능 향상 을 위해 here 문자열 을 사용 하여이 작업을 단순화 할 수 cut -d. -3f- <<<"$record"있습니다. 우리는 cut두 가지를 말합니다 : 먼저 , 구분자 를 사용 하는 -d것처럼 필드를 식별하기위한 특정 구분자가 있어야합니다 . 두 번째 는 특정 필드의 값만 인쇄 하도록 지시 합니다. 필드 목록은 세 번째 필드와 모든 다음 필드의 값을 나타내는 범위로 제공됩니다. 즉 , 레코드에서 찾은 초 를 포함하여 모든 것을 읽고 무시한 다음 파일 경로 부분 인 나머지를 인쇄합니다.sort.cut-f3-cut.

최신 파일 경로를 인쇄하면 계속 진행할 필요가 없습니다 break. 두 번째 파일 경로로 이동하지 않고 루프를 종료합니다.

남아있는 유일한 것은 tail이 파이프 라인이 반환 한 파일 경로에서 실행 중 입니다. 필자의 예제에서 파이프 라인을 서브 쉘로 묶어이 작업을 수행했음을 알 수 있습니다. 눈치 채지 못한 것은 서브 쉘을 큰 따옴표로 묶었다는 것입니다. 파일 이름을 안전하게 보호하기 위해이 모든 노력을 기울여도 인용되지 않은 서브 쉘 확장으로 인해 여전히 문제가 발생할 수 있기 때문에 이것은 중요합니다. 자세한 설명은 당신이 관심이 있다면 사용할 수 있습니다. 두 번째 중요하지만 간과하기 쉬운 측면 은 파일 이름을 확장하기 전에 tail옵션 --을 제공했다는 것 입니다. 이것은 지시합니다tail더 이상 옵션을 지정하지 않고 다음에 나오는 모든 파일 이름은 파일 이름이므로로 시작하는 파일 이름을 안전하게 처리 할 수 ​​있습니다 -.


답변

tail `ls -t | head -1`

공백이있는 파일 이름이 걱정된다면

tail "`ls -t | head -1`"

답변

당신이 사용할 수있는:

tail $(ls -1t | head -1)

$()구조는 명령을 실행하는 하위 쉘 시작 ls -1t이를 통해 배관 (모든 시간 순서로 파일을 한 줄에 하나씩 나열) head -1첫 번째 줄 (파일)을 얻을합니다.

그런 다음 해당 명령 (가장 최근 파일)의 출력이 전달되어 tail처리됩니다.

가장 최근에 작성된 디렉토리 항목 인 경우 디렉토리를 가져올 위험이 있습니다. 별칭으로 트릭을 사용하여 해당 로그 파일 만 포함 된 디렉토리에서 가장 최근의 로그 파일 (회전 집합의)을 편집했습니다.


답변

POSIX 시스템에서는 “마지막으로 생성 된”디렉토리 항목을 얻는 방법이 없습니다. 각 디렉토리 항목이 atime, mtime그리고 ctime하지만, 마이크로 소프트 윈도우에 반하는은은 ctime“마지막 상태 변경의 시간”평균 CREATIONTIME을하지 않습니다,하지만.

그래서 당신이 얻을 수있는 최선의 방법은 “최근에 마지막으로 수정 된 파일을 맞추는 것”입니다. 이것은 다른 답변에서 설명합니다. 나는이 명령에 갈 것입니다 :

tail -f "$ (ls -tr | sed 1q)"

ls명령 주위에 따옴표를 적어 둡니다 . 스 니펫은 거의 모든 파일 이름으로 작동합니다.


답변

시계를 사용할 수있는 파일 크기 변경을보고 싶습니다.

watch -d ls -l

답변

에서 zsh:

tail *(.om[1])

다음을 참조하십시오 : http://zsh.sourceforge.net/Doc/Release/Expansion.html#Glob-Qualifiers , 여기에서 m수정 시간을 나타내며 m[Mwhms][-|+]n, 앞의 o방법은 한 방법으로 정렬됨을 의미합니다 ( O다른 방법으로 정렬). .유일한 수단 일반 파일. 괄호 안에서 [1]첫 번째 항목을 선택합니다. [1,3]가장 오래된 사용을 얻기 위해 세 가지 사용을 선택 합니다 [-1].

짧고 사용하지 않습니다 ls.


답변

이 작업을 수행하는 백만 가지 방법이있을 수 있지만 내가하는 방법은 다음과 같습니다.

tail `ls -t | head -n 1`

백틱 사이의 비트 (문자와 같은 따옴표)가 해석되고 결과가 tail로 리턴됩니다.

ls -t #gets the list of files in time order
head -n 1 # returns the first line only