Nhận tệp gần đây nhất trong một thư mục trên Linux


181

Tìm kiếm một lệnh sẽ trả về tập tin gần đây nhất trong một thư mục.

Không thấy tham số giới hạn đối với ls...


1
watch -n1 'ls -Art | tail -n 1'- hiển thị các tệp cuối cùng

Hầu hết các câu trả lời ở đây phân tích đầu ra lshoặc sử dụng findmà không -print0có vấn đề gì để xử lý các tên tệp gây phiền nhiễu. Luôn luôn hữu ích để đề cập: BashFAQ099 đưa ra câu trả lời POSIX cho vấn đề này
kaugeour

Câu trả lời:


264
ls -Art | tail -n 1

Không thanh lịch, nhưng nó hoạt động.


2
sử dụng ls -Artls bạn cũng có thể xem ngày của tập tin.
Josir

13
Một vấn đề nhỏ: Phiên bản này Ống tất cả các đầu ra của lsđể tail, sau đó in chỉ dòng cuối cùng. IMHO tốt hơn là sắp xếp theo thứ tự tăng dần và sử dụng headthay thế, như được chaosđề xuất. Sau khi in các đầu ra dòng đầu tiên, do đó, gửi dòng tiếp theo (thực sự là khối tiếp theo) sẽ tăng SIGPIPE và lscũng sẽ thoát.
TrueY

1
@TrueY Tôi khá đồng ý. Câu trả lời của Chaos là tốt hơn cho hiệu quả.
dmckee --- ex-moderator mèo con

2
Lưu ý rằng giải pháp này bao gồm các thư mục cũng như các tập tin. Đây có thể là một điều tốt hoặc một điều xấu; nó phụ thuộc vào những gì người dùng cá nhân muốn. Lý do tôi đưa ra điều này là câu hỏi ban đầu nói "tập tin".
Sildoreth 13/03/2015

2
Tôi nghĩ rằng lợi ích dự định của việc sử dụng đuôi thay vì đầu có thể là loại trừ việc bao gồm dòng mô tả tổng số được trả về bởi ls.
Peter Scott

155
ls -t | head -n1

Lệnh này thực sự cung cấp cho tập tin sửa đổi mới nhất trong thư mục làm việc hiện tại.


Tương đương với tôi, và có thể hiệu quả hơn, quá.
dmckee --- ex-moderator mèo con

không hoàn toàn phù hợp với tôi vì tôi lặp lại một số thông tin trong ls của tôi trước, nhưng tôi có được cách sử dụng, cảm ơn!
ack

4
@Josir Điều này có thể được sửa đổi để bao gồm dấu dữ liệu với ls -tl | head -n 1và nó không phải đẩy toàn bộ bảng thông qua đường ống theo cách của tôi.
dmckee --- ex-moderator mèo con

1
@ noɥʇʎԀʎzɐɹƆls -t *.png | head -n1
hỗn loạn

4
Điều này trả về một thư mục nếu đó là bản sửa đổi mới nhất, hãy sử dụng: ls -Art | head -n1nếu bạn đặc biệt muốn tệp được sửa đổi mới nhất
achasinh

79

Đây là phiên bản đệ quy (tức là nó tìm thấy tệp được cập nhật gần đây nhất trong một thư mục nhất định hoặc bất kỳ thư mục con nào của nó)

find $DIR -type f -printf "%T@ %p\n" | sort -n | cut -d' ' -f 2- | tail -n 1

Chỉnh sửa: sử dụng -f 2-thay vì -f 2theo đề xuất của Kevin


5
Đây là một giải pháp cho Mac:find $DIR -type f -exec stat -lt "%Y-%m-%d" {} \+ | cut -d' ' -f6- | sort -n | tail -1
người dùng

2
Vấn đề là lệnh cắt cắt các đường dẫn có khoảng trắng thay vì -f 2 sử dụng -f2- để trả các trường 2 về cuối dòng
Kevin

2
Như trong gợi ý của sự hỗn loạn, nếu bạn đảo ngược sắp xếp bằng cách sử dụng sort -nr, bạn có thể sử dụng head -n 1thay vì tail -n 1và cải thiện hiệu quả một chút. (Mặc dù nếu bạn đang sắp xếp một tìm kiếm đệ quy, việc nhận được dòng đầu tiên hoặc dòng cuối cùng sẽ không phải là phần chậm.)
Destenson

2
Rất hữu ích! Tôi thấy nó thân thiện hơn nếu được dẫn đến ls mặc dù:find ./ -type f -printf "%T@ %p\n" -ls | sort -n | cut -d' ' -f 2- | tail -n 1 | xargs -r ls -lah
Simon

@ phiên bản Mac của người dùng chỉ sắp xếp / hiển thị ngày, không phải thời gian. Đây là phiên bản cố định:find $DIR -type f -exec stat -lt "%F %T" {} \+ | cut -d' ' -f6- | sort -n | tail -1
yoz

11

Một lưu ý về độ tin cậy:

Vì ký tự dòng mới có giá trị như bất kỳ tên tệp nào, nên bất kỳ giải pháp nào dựa trên các dòng như head/ taildựa trên đều thiếu sót.

Với GNU ls, một tùy chọn khác là sử dụng --quoting-style=shell-alwaystùy chọn và một bashmảng:

eval "files=($(ls -t --quoting-style=shell-always))"
((${#files[@]} > 0)) && printf '%s\n' "${files[0]}"

(thêm -Atùy chọn vào lsnếu bạn cũng muốn xem xét các tệp ẩn).

Nếu bạn muốn giới hạn các tệp thông thường (bỏ qua các thư mục, fifos, thiết bị, liên kết tượng trưng, ​​ổ cắm ...), bạn cần phải sử dụng GNU find.

Với bash 4.4 hoặc mới hơn (for readarray -d) và GNU coreutils 8.25 hoặc mới hơn (for cut -z):

readarray -t -d '' files < <(
  LC_ALL=C find . -maxdepth 1 -type f ! -name '.*' -printf '%T@/%f\0' |
  sort -rzn | cut -zd/ -f2)

((${#files[@]} > 0)) && printf '%s\n' "${files[0]}"

Hoặc đệ quy:

readarray -t -d '' files < <(
  LC_ALL=C find . -name . -o -name '.*' -prune -o -type f -printf '%T@%p\0' |
  sort -rzn | cut -zd/ -f2-)

Tốt nhất ở đây sẽ là sử dụng zshvà vòng loại toàn cầu của nó thay vì bashđể tránh tất cả những rắc rối này:

Tập tin mới nhất trong thư mục hiện tại:

printf '%s\n' *(.om[1])

Bao gồm những cái ẩn:

printf '%s\n' *(D.om[1])

Thứ hai mới nhất:

printf '%s\n' *(.om[2])

Kiểm tra tuổi tập tin sau khi phân giải symlink:

printf '%s\n' *(-.om[1])

Đệ quy:

printf '%s\n' **/*(.om[1])

Ngoài ra, với hệ thống hoàn thành ( compinitvà đồng) được bật, Ctrl+Xmtrở thành trình hoàn thành mở rộng sang tệp mới nhất.

Vì thế:

vi Ctrl+Xm

Sẽ khiến bạn chỉnh sửa tệp mới nhất (bạn cũng có cơ hội xem tệp nào trước khi nhấn Return).

vi Alt+2Ctrl+Xm

Đối với tập tin mới nhất thứ hai.

vi * .cCtrl+Xm

cho ctập tin mới nhất .

vi * (.)Ctrl+Xm

cho tệp thông thường mới nhất (không phải thư mục, cũng không phải fifo / thiết bị ...), v.v.


Cảm ơn zshlời khuyên. Bạn có thể cung cấp một liên kết để biết thêm chi tiết về điều này trong tài liệu zsh?
đóng băng

@freened, xeminfo zsh qualifiers
Stephane Chazelas

Cảm ơn @Stephane Chazelas
đóng băng

9

Tôi sử dụng:

ls -ABrt1 --group-directories-first | tail -n1

Nó chỉ cho tôi tên tập tin, không bao gồm các thư mục.


trừ khi một thư mục chỉ có các thư mục
ealfonso 27/11/13

8

ls -lAtr | tail -1

Các giải pháp khác không bao gồm các tập tin bắt đầu với '.'.

Lệnh này cũng sẽ bao gồm '.''..', có thể hoặc không thể là những gì bạn muốn:

ls -latr | tail -1


Điều này sẽ trở lại "." nếu thư mục đã được sửa đổi gần đây hơn bất kỳ tập tin nào chứa (nói bằng cách xóa)? Có lẽ đó là hành vi mong muốn, có thể không. Nhưng bạn cũng đúng.
dmckee --- ex-moderator mèo con

6

Biến thể rút gọn dựa trên câu trả lời của dmckee:

ls -t | head -1

nhưng -1cú pháp đánh đầu đã bị phản đối cách đây khá lâu và -n 1nên được sử dụng.
tink

5

Tôi thích echo *(om[1])( zshcú pháp) vì nó chỉ cung cấp tên tệp và không gọi bất kỳ lệnh nào khác.


1
Hoạt động tốt nếu bạn đang sử dụng zsh. Bạn không sử dụng zsh? Tôi nghĩ bash là mặc định trong Ubuntu; bạn có thể cài đặt zsh hoặc bạn có thể tìm thấy một lệnh tương đương cho bash.
MikeB

3
Lệnh là "echo"; nó chỉ đánh giá các tham số của nó và gửi chúng đến đầu ra tiêu chuẩn. Trong trường hợp này, vòng loại toàn cầu "om [1]" có "o", có nghĩa là sắp xếp các tệp phù hợp theo "m", thời gian được sửa đổi. Và từ danh sách được sắp xếp đó, lấy [1], đây là tệp đầu tiên. Bạn có thể đọc về vòng loại glob: zsh.sourceforge.net/Doc/Release/Expansion.html#Glob-Qualifiers
MikeB

4

Giải pháp find / sort hoạt động tuyệt vời cho đến khi số lượng tệp thực sự lớn (như toàn bộ hệ thống tệp). Thay vào đó, hãy sử dụng awk để theo dõi tệp gần đây nhất:

find $DIR -type f -printf "%T@ %p\n" | 
awk '
BEGIN { recent = 0; file = "" }
{
if ($1 > recent)
   {
   recent = $1;
   file = $0;
   }
}
END { print file; }' |
sed 's/^[0-9]*\.[0-9]* //'

3

Cá nhân tôi thích sử dụng ít lệnh không tích hợp bashnhất có thể (để giảm số lượng ngã ba đắt tiền và thực hiện các tòa nhà cao tầng). Để sắp xếp theo ngày lscần thiết để được gọi. Nhưng sử dụng headlà không thực sự cần thiết. Tôi sử dụng một lớp lót sau (chỉ hoạt động trên các hệ thống hỗ trợ ống tên):

read newest < <(ls -t *.log)

hoặc để có được tên của tập tin cũ nhất

read oldest < <(ls -rt *.log)

(Lưu ý khoảng trắng giữa hai dấu '<'!)

Nếu các tập tin ẩn cũng cần thiết -A arg có thể được thêm vào.

Tôi hy vọng điều này có thể giúp đỡ.


Bạn nên giải thích rằng tên tệp được lưu trữ trong $ old / var mới nhất. Nhưng +1 cho số lượng dĩa ít nhất.
squareatom

@squareatom Tôi nghĩ rằng đọc khá rõ được tích hợp sẵn. Nhưng bạn nói đúng, có thể không. Cám ơn bạn đã góp ý!
TrueY

3
Giả sử bạn biết tích hợp là gì, bạn đã thăm dò chính xác. Nhưng, tôi chỉ nghĩ về câu hỏi của OP. Họ yêu cầu một lệnh sẽ trả lại một cái gì đó. Về mặt kỹ thuật, giải pháp của bạn không tạo ra bất cứ điều gì. Vì vậy, chỉ cần thêm "&& echo $ mới nhất" hoặc tương tự vào cuối ;-)
squareatom

3

sử dụng tùy chọn đệ quy R .. bạn có thể coi đây là phần nâng cao cho câu trả lời hay tại đây

ls -arRtlh | tail -50

2
ls -t -1 | sed '1q'

Sẽ hiển thị các mục sửa đổi cuối cùng trong thư mục. Ghép nối grepđể tìm mục mới nhất với từ khóa

ls -t -1 | grep foo | sed '1q'

'1q' là gì? 1là cho dòng đầu tiên tương đương với head -n 1q là gì?
HattrickNZ

2

Đệ quy:

find $1 -type f -exec stat --format '%Y :%y %n' "{}" \; | sort -nr | cut -d: -f2- | head

1

thử lệnh đơn giản này

ls -ltq  <path>  | head -n 1

Nếu bạn muốn tên tệp - được sửa đổi lần cuối, path = /ab/cd/*.log

Nếu bạn muốn tên thư mục - sửa đổi lần cuối, đường dẫn = / ab / cd / * /


1

Giả sử bạn không quan tâm đến các tập tin ẩn bắt đầu bằng một .

ls -rt | tail -n 1

Nếu không thì

ls -Art | tail -n 1

1

Chỉ với các nội dung Bash, theo sát BashFAQ / 003 :

shopt -s nullglob

for f in * .*; do
    [[ -d $f ]] && continue
    [[ $f -nt $latest ]] && latest=$f
done

printf '%s\n' "$latest"

0

Tất cả các giải pháp ls / tail hoạt động hoàn toàn tốt cho các tệp trong một thư mục - bỏ qua các thư mục con.

Để bao gồm tất cả các tệp trong tìm kiếm của bạn (đệ quy), find có thể được sử dụng. gioele đề nghị sắp xếp đầu ra tìm định dạng. Nhưng hãy cẩn thận với khoảng trắng (đề xuất của anh ấy không hoạt động với khoảng trắng).

Điều này sẽ làm việc với tất cả các tên tệp:

find $DIR -type f -printf "%T@ %p\n" | sort -n | sed -r 's/^[0-9.]+\s+//' | tail -n 1 | xargs -I{} ls -l "{}"

Điều này sắp xếp theo mtime, xem người đàn ông tìm thấy:

%Ak    File's  last  access  time in the format specified by k, which is either `@' or a directive for the C `strftime' function.  The possible values for k are listed below; some of them might not be available on all systems, due to differences in `strftime' between systems.
       @      seconds since Jan. 1, 1970, 00:00 GMT, with fractional part.
%Ck    File's last status change time in the format specified by k, which is the same as for %A.
%Tk    File's last modification time in the format specified by k, which is the same as for %A.

Vì vậy, chỉ cần thay thế %Tvới %Cđể sắp xếp theo ctime.


Bạn đã đúng về vấn đề khoảng trắng với đề xuất @gioele, nhưng bạn chỉ cần thêm dấu gạch nối vào tùy chọn -f để biến nó thành một phạm vi để khắc phục điều đó: find $DIR -type f -printf "%T@ %p\n" | sort -n | cut -d' ' -f 2- | tail -n 1 Hoặc cách khác, giữ tất cả ngoại trừ trường đầu tiên: find $DIR -type f -printf "%T@ %p\n" | sort -n | cut -d' ' -f 1 --complement | tail -n 1
Aaron

0

Tìm tệp mới nhất trong mọi thư mục theo một mẫu, ví dụ: các thư mục con của thư mục làm việc có tên kết thúc bằng "tmp" (không phân biệt chữ hoa chữ thường):

find . -iname \*tmp -type d -exec sh -c "ls -lArt {} | tail -n 1" \;

0
ls -Frt | grep "[^/]$" | tail -n 1

1
Có những câu trả lời khác cung cấp câu hỏi của OP và chúng đã được đăng từ nhiều năm trước. Khi đăng câu trả lời, vui lòng đảm bảo bạn thêm một giải pháp mới hoặc giải thích rõ ràng hơn, đặc biệt là khi trả lời các câu hỏi cũ hơn.
help-info.de

2
@ help-info.de Vui lòng không bỏ phiếu để xóa các câu trả lời chỉ có mã. Chúng có thể không tuyệt vời, nhưng việc xóa là dành cho những thứ không phải là câu trả lời
Machavity

@Machavity - Tôi hy vọng không thất bại và chỉ nhận xét cho câu trả lời muộn.
help-info.de

0

Nếu bạn muốn nhận tệp thay đổi gần đây nhất, bao gồm mọi thư mục con bạn có thể thực hiện với oneliner nhỏ này:

find . -type f -exec stat -c '%Y %n' {} \; | sort -nr | awk -v var="1" 'NR==1,NR==var {print $0}' | while read t f; do d=$(date -d @$t "+%b %d %T %Y"); echo "$d -- $f"; done

Nếu bạn muốn làm tương tự không phải đối với các tệp đã thay đổi, nhưng đối với các tệp được truy cập, bạn đơn giản phải thay đổi

% Y tham số từ các stat lệnh để % X . Và lệnh của bạn cho hầu hết các tệp được truy cập gần đây trông như thế này:

find . -type f -exec stat -c '%X %n' {} \; | sort -nr | awk -v var="1" 'NR==1,NR==var {print $0}' | while read t f; do d=$(date -d @$t "+%b %d %T %Y"); echo "$d -- $f"; done

Đối với cả hai lệnh, bạn cũng có thể thay đổi tham số var = "1" nếu bạn muốn liệt kê nhiều hơn chỉ một tệp.


-1

Tôi cũng cần phải làm điều đó và tôi đã tìm thấy những lệnh này. những công việc này cho tôi:

Nếu bạn muốn tập tin cuối cùng trước ngày tạo trong thư mục (thời gian truy cập):

ls -Aru | tail -n 1  

Và nếu bạn muốn tập tin cuối cùng có thay đổi trong nội dung của nó (sửa đổi thời gian):

ls -Art | tail -n 1  
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.