รับไฟล์ล่าสุดในไดเรกทอรีบน Linux


183

ค้นหาคำสั่งที่จะส่งคืนไฟล์ล่าสุดในไดเรกทอรี

ไม่เห็นพารามิเตอร์ จำกัด ถึงls...


1
watch -n1 'ls -Art | tail -n 1'- แสดงไฟล์ล่าสุด

คำตอบส่วนใหญ่ที่นี่แจงเอาท์พุทlsหรือการใช้งานที่findไม่มี-print0ปัญหาในการจัดการชื่อไฟล์ที่น่ารำคาญ มีประโยชน์เสมอที่จะกล่าวถึง: BashFAQ099ซึ่งให้คำตอบกับ POSIX สำหรับปัญหานี้
kvantour

คำตอบ:


266
ls -Art | tail -n 1

ไม่หรูหรามาก แต่ใช้งานได้


2
ใช้ ls -Artls คุณยังสามารถดูวันที่ของไฟล์ได้
Josir

13
ปัญหาเล็กน้อย: รุ่นนี้ส่งออกlsไปยังท่อทั้งหมดtailแล้วพิมพ์เฉพาะบรรทัดสุดท้าย IMHO มันจะดีกว่าที่จะเรียงลำดับจากน้อยไปมากและใช้headแทนตามที่chaosแนะนำ หลังจากการพิมพ์ส่วนหัวบรรทัดแรกหยุดทำงานดังนั้นการส่งบรรทัดถัดไป (จริง ๆ แล้วบล็อกถัดไป) จะเพิ่ม SIGPIPE และlsจะปิดเช่นกัน
TrueY

1
@ True ฉันค่อนข้างเห็นด้วย คำตอบของความโกลาหลดีกว่าเพื่อประสิทธิภาพ
dmckee --- ผู้ดูแลอดีตลูกแมว

2
โปรดทราบว่าวิธีนี้รวมถึงไดเรกทอรีเช่นเดียวกับไฟล์ นี่อาจเป็นสิ่งที่ดีหรือไม่ดี; มันขึ้นอยู่กับสิ่งที่ผู้ใช้แต่ละคนต้องการ เหตุผลที่ฉันนำมาใช้คือคำถามเดิมบอกว่า "ไฟล์"
Sildoreth

2
ฉันคิดว่าประโยชน์ที่ตั้งใจไว้ของการใช้หางแทนที่จะเป็นหัวอาจยกเว้นการรวมบรรทัดที่อธิบายถึงผลตอบแทนทั้งหมดโดย ls
ปีเตอร์สกอตต์

155
ls -t | head -n1

คำสั่งนี้ให้ไฟล์ที่แก้ไขล่าสุดในไดเร็กทอรีการทำงานปัจจุบันจริง ๆ


เทียบเท่ากับของฉันและอาจมีประสิทธิภาพมากกว่าด้วย
dmckee --- ผู้ดูแลอดีตลูกแมว

ไม่ได้ผลสำหรับฉันเนื่องจากฉันสะท้อนข้อมูลบางอย่างใน ls ของฉันก่อน แต่ฉันได้รับการใช้งานขอบคุณ!
ack

4
@Josir สิ่งนี้สามารถแก้ไขได้เพื่อรวม datestamp ด้วยls -tl | head -n 1และไม่จำเป็นต้องผลักทั้งตารางผ่านทางท่อในแบบที่ฉันทำ
dmckee --- ผู้ดูแลอดีตลูกแมว

1
@ noɥʇʎԀʎzɐɹƆls -t *.png | head -n1
ความโกลาหล

4
นี่จะส่งคืนโฟลเดอร์หากเป็นไฟล์ที่แก้ไขล่าสุดให้ใช้: ls -Art | head -n1หากคุณต้องการไฟล์ที่แก้ไขล่าสุดโดยเฉพาะ
achasinh

79

นี่เป็นเวอร์ชันแบบเรียกซ้ำ (เช่นจะค้นหาไฟล์ที่อัพเดตล่าสุดในไดเรกทอรีหนึ่ง ๆ หรือไดเรกทอรีย่อยใด ๆ )

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

แก้ไข: ใช้-f 2-แทน-f 2ตามที่เควินแนะนำ


5
นี่เป็นวิธีแก้ปัญหาสำหรับ Mac:find $DIR -type f -exec stat -lt "%Y-%m-%d" {} \+ | cut -d' ' -f6- | sort -n | tail -1
ผู้ใช้

2
ปัญหาคือคำสั่ง cut ตัดทอนพา ธ ด้วยช่องว่างแทน -f 2 ใช้ -f2- เพื่อส่งคืนฟิลด์ 2 ถึงจุดสิ้นสุดบรรทัด
Kevin

2
ในข้อเสนอแนะโดยความโกลาหลหากคุณย้อนกลับการเรียงลำดับโดยใช้sort -nrคุณสามารถใช้head -n 1แทนtail -n 1และปรับปรุงประสิทธิภาพได้เล็กน้อย ( แต่ถ้าคุณกำลังเรียงลำดับหา recursive รับบรรทัดแรกหรือสุดท้ายจะไม่เป็นส่วนหนึ่งช้า.)
destenson

2
มีประโยชน์มาก! ฉันคิดว่ามันเป็นมิตรมากกว่าถ้าส่งไปยัง ls:find ./ -type f -printf "%T@ %p\n" -ls | sort -n | cut -d' ' -f 2- | tail -n 1 | xargs -r ls -lah
Simon

เวอร์ชั่น Mac ของผู้ใช้ @ เรียงลำดับ / แสดงวันเท่านั้นไม่ใช่เวลา นี่คือรุ่นที่แก้ไขแล้ว:find $DIR -type f -exec stat -lt "%F %T" {} \+ | cut -d' ' -f6- | sort -n | tail -1
yoz

11

หมายเหตุเกี่ยวกับความน่าเชื่อถือ:

เนื่องจากอักขระขึ้นบรรทัดใหม่นั้นมีความถูกต้องเหมือนในชื่อไฟล์โซลูชันใด ๆ ที่อาศัยบรรทัดเช่นhead/ tailตามตัวอักษรนั้นมีข้อบกพร่อง

ด้วย GNU lsตัวเลือกอื่นคือใช้--quoting-style=shell-alwaysตัวเลือกและbashอาร์เรย์:

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

(เพิ่ม-Aตัวเลือกในlsหากคุณต้องการพิจารณาไฟล์ที่ซ่อนอยู่ด้วย)

หากคุณต้องการ จำกัด ไฟล์ปกติ (ไม่สนใจไดเรกทอรี, Fifos, อุปกรณ์, symlink, sockets ... ) คุณจะต้องหันไปใช้ GNU findGNU

ด้วย bash 4.4 หรือใหม่กว่า (สำหรับreadarray -d) และ GNU coreutils 8.25 หรือใหม่กว่า (สำหรับ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]}"

หรือเรียกซ้ำ:

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

สิ่งที่ดีที่สุดที่นี่คือการใช้zshและโปรแกรมคัดเลือกแบบกลมแทนที่จะbashหลีกเลี่ยงความยุ่งยากทั้งหมดนี้:

ไฟล์ปกติใหม่ล่าสุดในไดเรกทอรีปัจจุบัน:

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

รวมถึงรายการที่ซ่อนอยู่:

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

ใหม่สุดที่สอง:

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

ตรวจสอบอายุไฟล์หลังจากความละเอียด symlink:

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

ซ้ำ:

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

นอกจากนี้เมื่อcompinitเปิดใช้งานระบบเสร็จสมบูรณ์ ( และร่วม)Ctrl+Xmจะกลายเป็นคอมไพเลอร์ที่ขยายเป็นไฟล์ใหม่ล่าสุด

ดังนั้น:

vi Ctrl+Xm

จะทำให้คุณแก้ไขไฟล์ใหม่ล่าสุด (คุณยังมีโอกาสได้เห็นไฟล์ก่อนกด Return )

vi Alt+2Ctrl+Xm

สำหรับไฟล์ใหม่ล่าสุดที่สอง

vi * .cCtrl+Xm

สำหรับใหม่ล่าสุด cไฟล์

vi * (.)Ctrl+Xm

สำหรับไฟล์ปกติใหม่ล่าสุด(ไม่ใช่ไดเรกทอรีหรือ Fifo / อุปกรณ์ ... ) และอื่น ๆ


ขอบคุณสำหรับzshเคล็ดลับ คุณสามารถให้ลิงค์ไปยังรายละเอียดเพิ่มเติมเกี่ยวกับเรื่องนี้ในเอกสาร zsh ได้ไหม?
แช่แข็ง

@ ฟรีให้ดูinfo zsh qualifiers
Stephane Chazelas

ขอบคุณ @Stephane Chazelas
แช่แข็ง

9

ฉันใช้:

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

มันให้ฉันแค่ชื่อไฟล์ไม่รวมโฟลเดอร์


เว้นแต่ไดเรกทอรีมีไดเรกทอรีเท่านั้น
ealfonso

8

ls -lAtr | tail -1

โซลูชันอื่นไม่รวมไฟล์ที่ขึ้นต้นด้วย '.'ไม่รวมถึงไฟล์ที่เริ่มต้นด้วย

คำสั่งนี้จะรวมถึง'.'และ'..'ซึ่งอาจหรืออาจไม่ใช่สิ่งที่คุณต้องการ:

ls -latr | tail -1


สิ่งนี้จะส่งคืนหรือไม่ "." หากไดเรกทอรีได้รับการแก้ไขเร็วกว่าไฟล์ใด ๆ ที่มีอยู่ (พูดโดยการลบ)? บางทีนั่นอาจเป็นพฤติกรรมที่ต้องการก็ได้ แต่คุณก็ถูกทางใดทางหนึ่ง
dmckee --- ผู้ดูแลอดีตลูกแมว


5

ฉันชอบ echo *(om[1])( zshไวยากรณ์) ตามที่เพิ่งให้ชื่อไฟล์และไม่ได้เรียกคำสั่งอื่น ๆ


1
ทำงานได้ดีถ้าคุณใช้ zsh คุณไม่ได้ใช้ zsh หรือไม่? ฉันคิดว่า bash เป็นค่าเริ่มต้นใน Ubuntu; คุณสามารถติดตั้ง zsh หรือหาคำสั่งที่เทียบเท่าสำหรับ bash
MikeB

3
คำสั่งคือ "echo"; เพียงแค่ประเมินพารามิเตอร์และส่งไปยังเอาต์พุตมาตรฐาน ในกรณีนี้ตัวระบุแบบกลม "om [1]" มี "o" ซึ่งหมายถึงจัดเรียงไฟล์ที่ตรงกันด้วย "m" ซึ่งเป็นเวลาที่แก้ไข และจากรายการที่สั่งซื้อใช้ [1] ซึ่งเป็นไฟล์แรก คุณสามารถอ่านเกี่ยวกับตัวระบุแบบหมุนได้
MikeB

4

โซลูชัน find / sort ใช้งานได้ดีจนกระทั่งจำนวนไฟล์มีขนาดใหญ่มาก (เช่นระบบไฟล์ทั้งหมด) ใช้ awk แทนเพื่อติดตามไฟล์ล่าสุด:

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

โดยส่วนตัวฉันชอบที่จะใช้bashคำสั่งที่ไม่ได้มีให้ในตัวน้อยที่สุดเท่าที่จะทำได้ (เพื่อลดจำนวนส้อมและ exec syscalls ที่มีราคาแพง) หากต้องการจัดเรียงตามวันที่lsจำเป็นต้องเรียกใช้ แต่การใช้headไม่จำเป็นจริงๆ ฉันใช้หนึ่งซับต่อไปนี้ (ใช้ได้กับระบบที่รองรับท่อชื่อ):

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

หรือเพื่อรับชื่อไฟล์ที่เก่าที่สุด

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

(คำนึงถึงช่องว่างระหว่างเครื่องหมาย '<' สองอัน!)

หากไฟล์ที่ซ่อนอยู่ยังต้องการ -Ag สามารถเพิ่ม

ฉันหวังว่านี่จะช่วยได้


คุณควรอธิบายว่าชื่อไฟล์นั้นถูกเก็บไว้ในรูปแบบ $ เก่าที่สุด / ใหม่สุด แต่ +1 สำหรับส้อมอย่างน้อย
squareatom

@squareatom ฉันคิดว่าการอ่านมีความรู้ในตัวค่อนข้างดี แต่คุณพูดถูก ขอบคุณสำหรับความคิดเห็นของคุณ!
TrueY

3
สมมติว่าคุณรู้ว่าบิวด์อินคืออะไรคุณแก้ไขได้ถูกต้อง แต่ฉันแค่คิดถึงคำถามของ OP พวกเขาถามหาคำสั่งที่จะส่งคืนบางสิ่ง ในทางเทคนิคแล้วโซลูชันของคุณจะไม่แสดงผลใด ๆ ดังนั้นเพียงเพิ่ม "&& echo $ ใหม่ล่าสุด" หรือคล้ายกับส่วนท้าย ;-)
squareatom

3

ใช้ตัวเลือกแบบเรียกซ้ำ R .. คุณอาจถือว่านี่เป็นการปรับปรุงสำหรับคำตอบที่ดีที่นี่

ls -arRtlh | tail -50

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

จะแสดงรายการที่แก้ไขล่าสุดในโฟลเดอร์ จับคู่กับgrepเพื่อค้นหารายการล่าสุดด้วยคำหลัก

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

'1q' คืออะไร 1สำหรับบรรทัดแรกhead -n 1เท่ากับคิวคืออะไร?
HattrickNZ


1

ลองใช้คำสั่งง่ายๆนี้

ls -ltq  <path>  | head -n 1

หากคุณต้องการชื่อไฟล์ - แก้ไขล่าสุด path = /ab/cd/*.log

ถ้าคุณต้องการชื่อไดเรกทอรี - แก้ไขครั้งล่าสุด path = / ab / cd / * /


1

สมมติว่าคุณไม่สนใจไฟล์ที่ซ่อนที่เริ่มต้นด้วย .

ls -rt | tail -n 1

มิฉะนั้น

ls -Art | tail -n 1

1

ด้วย Bash builtins เท่านั้นติดตามBashFAQ / 003อย่างใกล้ชิด:

shopt -s nullglob

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

printf '%s\n' "$latest"

0

LS ทุกคน / แก้ปัญหาหางทำงานได้อย่างสมบูรณ์ดีสำหรับไฟล์ในไดเรกทอรี - ไดเรกทอรีย่อยละเลย

เพื่อที่จะรวมไฟล์ทั้งหมดในการค้นหาของคุณ (เรียกซ้ำ) คุณสามารถใช้ find ได้ gioele แนะนำให้เรียงลำดับผลลัพธ์การค้นหาที่จัดรูปแบบ แต่ระวังด้วย whitespaces (คำแนะนำของเขาใช้ไม่ได้กับ whitespaces)

สิ่งนี้ควรใช้กับชื่อไฟล์ทั้งหมด:

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

เรียงลำดับตามเวลาดูคนค้นหา:

%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.

ดังนั้นแทนที่%Tด้วย%Cการจัดเรียงตามเวลา


คุณถูกต้องเกี่ยวกับปัญหาพื้นที่สีขาวด้วยคำแนะนำ @gioele แต่คุณจะต้องเพิ่มยัติภังค์ในตัวเลือก -f เพื่อให้เป็นช่วงเพื่อแก้ไข: find $DIR -type f -printf "%T@ %p\n" | sort -n | cut -d' ' -f 2- | tail -n 1 หรือมิฉะนั้นให้เก็บทั้งหมดยกเว้นฟิลด์แรก: find $DIR -type f -printf "%T@ %p\n" | sort -n | cut -d' ' -f 1 --complement | tail -n 1
Aaron

0

การค้นหาไฟล์ล่าสุดในทุกไดเรกทอรีตามรูปแบบเช่นไดเรกทอรีย่อยของไดเรกทอรีทำงานที่มีชื่อลงท้ายด้วย "tmp" (ไม่คำนึงถึงขนาดตัวพิมพ์):

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

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

1
มีคำตอบอื่น ๆ ที่ให้คำถามของ OP และพวกเขาโพสต์เมื่อหลายปีก่อน เมื่อโพสต์คำตอบโปรดตรวจสอบให้แน่ใจว่าคุณได้เพิ่มโซลูชันใหม่หรือคำอธิบายที่ดีขึ้นอย่างมากโดยเฉพาะเมื่อตอบคำถามรุ่นเก่า
help-info.de

2
@ help-info.de โปรดอย่าโหวตให้ลบคำตอบที่เป็นรหัสเท่านั้น พวกเขาอาจจะไม่ดี แต่การลบสำหรับสิ่งที่ไม่ใช่คำตอบ
Machavity

@Machavity - ฉันหวังว่าจะไม่ล้มเหลวและได้แสดงความคิดเห็นสำหรับคำตอบที่ล่าช้าเท่านั้น
help-info.de

0

หากคุณต้องการรับไฟล์ที่มีการเปลี่ยนแปลงล่าสุดรวมถึงไดเรกทอรีย่อยใด ๆ คุณสามารถทำได้ด้วย oneliner ตัวน้อยนี้:

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

หากคุณต้องการทำสิ่งเดียวกันไม่ใช่สำหรับไฟล์ที่ถูกเปลี่ยน แต่สำหรับไฟล์ที่เข้าถึงคุณต้องเปลี่ยน

% Yพารามิเตอร์จากสถิติคำสั่งX% และคำสั่งของคุณสำหรับไฟล์ที่เข้าถึงล่าสุดมีลักษณะดังนี้:

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

สำหรับทั้งคำสั่งคุณยังสามารถเปลี่ยนพารามิเตอร์var = "1"หากคุณต้องการแสดงรายการมากกว่าหนึ่งไฟล์


-1

ฉันจำเป็นต้องทำเช่นกันและฉันพบคำสั่งเหล่านี้ งานเหล่านี้สำหรับฉัน:

หากคุณต้องการไฟล์ล่าสุดตามวันที่สร้างในโฟลเดอร์ (เวลาเข้าถึง):

ls -Aru | tail -n 1  

และหากคุณต้องการไฟล์ล่าสุดที่มีการเปลี่ยนแปลงเนื้อหา (แก้ไขเวลา):

ls -Art | tail -n 1  
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.