답변:
마십시오 하지 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 형식 을 묻습니다 . %p
null 바이트로 끝나기 전에이 다른 기간을 추가 한 다음 (파일의 전체 경로)를 추가합니다.
지금 나 한테있어
find . -maxdepth 1 \! -type d -printf '%T@.%p\0'
말할 것도없이 완료 될 수 있지만 하위 디렉토리의 내용을 나열 -maxdepth 1
하지 못하게 하고 원하지 않는 디렉토리는 건너 뜁니다 . 지금까지 수정 시간 정보가있는 현재 디렉토리에 파일이 있으므로 수정 시간을 기준으로 정렬해야합니다.find
\! -type d
tail
기본적 sort
으로 입력은 개행으로 구분 된 레코드 일 것으로 예상합니다. GNU를 가지고 있다면 스위치 sort
를 사용하여 대신 널로 구분 된 레코드를 요구할 수 있습니다 -z
.; 표준의 sort
경우 해결책이 없습니다. 나는 처음 두 숫자 (초와 초의 분수)로만 정렬하고 실제 파일 이름으로 정렬하고 싶지 않으므로 sort
두 가지를 말하고 싶습니다 . 먼저, .
필드 구분 기호 (마침표 ( )를 고려해야 함 ) 둘째, 레코드 정렬 방법을 고려할 때 첫 번째 필드와 두 번째 필드 만 사용해야합니다.
| sort -znr -t. -k1,2
우선, 나는 가치를 함께 취하지 않는 세 가지 짧은 옵션을 묶습니다. -znr
간결한 말입니다 -z -n -r
). 그 후 -t .
(공백은 선택 사항 임) sort
필드 구분 문자를 알려주고 -k 1,2
필드 번호를 지정합니다 : first 및 second ( sort
0이 아닌 1부터 필드를 계산). 현재 디렉토리의 샘플 레코드는 다음과 같습니다.
1000000000.0000000000../some-file-name
즉 , 이 레코드를 주문할 때 sort
먼저 확인해야 합니다. 이 옵션은 두 값이 모두 숫자이므로이 값을 비교할 때 숫자 비교를 사용하도록 지시 합니다. 숫자의 길이는 고정되어 있지만 해를 끼치 지 않으므로 중요하지 않을 수 있습니다.1000000000
0000000000
-n
sort
다른 스위치 sort
는 -r
"reverse"입니다. 기본적으로 숫자 정렬의 출력은 가장 낮은 숫자부터 시작 -r
하여 가장 낮은 숫자와 가장 높은 숫자를 먼저 나열하도록 변경합니다. 이 숫자는 타임 스탬프가 높을수록 더 새로운 것을 의미하므로 목록의 시작 부분에 최신 레코드가 저장됩니다.
파일 경로 목록이 나오면 sort
이제 원하는 답을 찾을 수 있습니다. 남은 것은 다른 레코드를 삭제하고 타임 스탬프를 제거하는 방법을 찾는 것입니다. 불행하게도, 심지어 GNU는 head
하고 tail
그들이 널 (null)로 구분 된 입력을 작동 할 수 있도록 스위치를 허용하지 않습니다. 대신 나는 while 루프를 가난한 사람의 일종으로 사용합니다 head
.
| while IFS= read -r -d '' record
먼저 IFS
파일 목록에 단어 분할이 적용 되지 않도록 설정을 해제했습니다 . 다음으로 나는 read
두 가지를 말한다 : 입력 ( -r
) 에서 이스케이프 시퀀스를 해석하지 말고 입력은 널 바이트 ( -d
)로 구분된다 ; 여기서 빈 문자열 ''
은 "구분 기호 없음"을 일명 null로 구분하는 데 사용됩니다. 루프를 반복 할 record
때마다 while
단일 타임 스탬프와 단일 파일 이름을 갖도록 각 레코드를 변수로 읽어들 입니다. 참고 -d
GNU 확장이다; 표준 만있는 read
경우이 기술은 작동하지 않으며 약간의 의지가 있습니다.
우리는 알고 record
변수가 모든 기간 문자로 구분이 세 부분을 가지고 있습니다. 은 Using cut
유틸리티를 그들 중 일부를 추출하는 것이 가능하다.
printf '%s' "$record" | cut -d. -f3-
여기에서 전체 레코드가 printf
파이프로 전달 됩니다 cut
. bash 에서는 성능 향상 을 위해 here 문자열 을 사용 하여이 작업을 단순화 할 수 cut -d. -3f- <<<"$record"
있습니다. 우리는 cut
두 가지를 말합니다 : 먼저 , 구분자 를 사용 하는 -d
것처럼 필드를 식별하기위한 특정 구분자가 있어야합니다 . 두 번째 는 특정 필드의 값만 인쇄 하도록 지시 합니다. 필드 목록은 세 번째 필드와 모든 다음 필드의 값을 나타내는 범위로 제공됩니다. 즉 , 레코드에서 찾은 초 를 포함하여 모든 것을 읽고 무시한 다음 파일 경로 부분 인 나머지를 인쇄합니다.sort
.
cut
-f
3-
cut
.
최신 파일 경로를 인쇄하면 계속 진행할 필요가 없습니다 break
. 두 번째 파일 경로로 이동하지 않고 루프를 종료합니다.
남아있는 유일한 것은 tail
이 파이프 라인이 반환 한 파일 경로에서 실행 중 입니다. 필자의 예제에서 파이프 라인을 서브 쉘로 묶어이 작업을 수행했음을 알 수 있습니다. 눈치 채지 못한 것은 서브 쉘을 큰 따옴표로 묶었다는 것입니다. 파일 이름을 안전하게 보호하기 위해이 모든 노력을 기울여도 인용되지 않은 서브 쉘 확장으로 인해 여전히 문제가 발생할 수 있기 때문에 이것은 중요합니다. 자세한 설명은 당신이 관심이 있다면 사용할 수 있습니다. 두 번째 중요하지만 간과하기 쉬운 측면 은 파일 이름을 확장하기 전에 tail
옵션 --
을 제공했다는 것 입니다. 이것은 지시합니다tail
더 이상 옵션을 지정하지 않고 다음에 나오는 모든 파일 이름은 파일 이름이므로로 시작하는 파일 이름을 안전하게 처리 할 수 있습니다 -
.
tail -f $(find . -type f -exec stat -f "%m {}" {} \;| sort -n | tail -n 1 | cut -d ' ' -f 2)
head
와 tail
그들이 널 (null)로 구분 된 입력을 작동 할 수 있도록 스위치를 허용하지 않습니다." 에 대한 나의 교체 head
: … | grep -zm <number> ""
.
tail `ls -t | head -1`
공백이있는 파일 이름이 걱정된다면
tail "`ls -t | head -1`"
당신이 사용할 수있는:
tail $(ls -1t | head -1)
$()
구조는 명령을 실행하는 하위 쉘 시작 ls -1t
이를 통해 배관 (모든 시간 순서로 파일을 한 줄에 하나씩 나열) head -1
첫 번째 줄 (파일)을 얻을합니다.
그런 다음 해당 명령 (가장 최근 파일)의 출력이 전달되어 tail
처리됩니다.
가장 최근에 작성된 디렉토리 항목 인 경우 디렉토리를 가져올 위험이 있습니다. 별칭으로 트릭을 사용하여 해당 로그 파일 만 포함 된 디렉토리에서 가장 최근의 로그 파일 (회전 집합의)을 편집했습니다.
-1
필요하지 않습니다 ls
이 파이프에 때 당신을 위해 작업을 수행합니다. 비교 ls
및 ls|cat
예를 들어,.
POSIX 시스템에서는 "마지막으로 생성 된"디렉토리 항목을 얻는 방법이 없습니다. 각 디렉토리 항목이 atime
, mtime
그리고 ctime
하지만, 마이크로 소프트 윈도우에 반하는은은 ctime
"마지막 상태 변경의 시간"평균 CREATIONTIME을하지 않습니다,하지만.
그래서 당신이 얻을 수있는 최선의 방법은 "최근에 마지막으로 수정 된 파일을 맞추는 것"입니다. 이것은 다른 답변에서 설명합니다. 나는이 명령에 갈 것입니다 :
tail -f "$ (ls -tr | sed 1q)"
ls
명령 주위에 따옴표를 적어 둡니다 . 스 니펫은 거의 모든 파일 이름으로 작동합니다.
에서 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
간단한:
tail -f /path/to/directory/*
나를 위해 잘 작동합니다.
tail 명령을 시작한 후 생성되는 파일을 얻는 것이 문제입니다. 그러나 필요하지 않으면 (위의 모든 솔루션이 신경 쓰지 않기 때문에) 별표는 더 간단한 솔루션 인 IMO입니다.
누군가가 그것을 게시 한 다음 어떤 이유로 든 지 웠지만 이것이 유일하게 작동합니다.
tail -f `ls -tr | tail`
ls
하는 것이 가장 현명한 일이 아니라는 것을 동의 한 이후에 삭제했습니다 .
tail -f `ls -lt | grep -v ^d | head -2 | tail -1 | tr -s " " | cut -f 8 -d " "`
설명: