Script สำหรับ หาวันที่ของไฟล์ล่าสุดใน directory

Q: ถ้าจะเขียน คำสั่ง หรือ script บน linux เพื่อหา วันที่ของ file ล่าสุดใน folder ของ user จะเขียนยังไงดี มีไอเดียไหมครับ

A: สมมติ folder ของ user คือ /home/user/Documents

$ ls -t /home/user/Documents

จะได้ไฟล์เรียงตามลำดับวันที่/เวลาของไฟล์ โดยไฟล์ล่าสุดจะโผล่มาเป็นไฟล์แรก

ถ้าเราต้องการไฟล์ล่าสุดแค่ไฟล์เดียว ก็สามารถใช้คำสั่ง head -1 เพื่อตัดให้เหลือไฟล์เดียวได้ ก็จะได้คำสั่งเป็น

$ ls -t /home/user/Documents | head -1

ทีนี้ จากชื่อไฟล์ที่ได้ ถ้าต้องการวันที่ เราก็สามารถใช้คำสั่ง date โดยใช้ option -r สำหรับให้มันแสดงวันที่ของไฟล์ใดๆ ตย. เช่น ต้องการรู้วันที่ ของไฟล์ /etc/passwd ก็ใช้คำสั่ง

$ date -r /etc/passwd

เอาสองอย่างนี้มาใช้งานร่วมกันได้ตามนี้ครับ

$ date -r `ls -t /home/user/Documents | head -1`

ทีนี้ ถ้าต้องการให้ format ของวันที่ออกมาตามที่เราต้องการ อย่างเช่น ให้ format เป็น yyyy-mm-dd HH:MM:SS
ก็เพิ่ม option ให้กับคำสั่ง date ประมาณนี้ “+%Y-%m-%d %H:%M:%S”

รวมกันทั้งหมดเป็น

$ date -r `ls -t /home/user/Documents | head -1` "+%Y-%m-%d %H:%M:%S"

Q: ถ้าจะลงลึกไปหลาย level ต้องทำอะไรเพิ่มครับ
A: หมายถึงต้องการไฟล์ล่าสุด ไฟล์เดียว จากใน directory นั้นและ sub directory ย่อยทั้งหมดใช่ใหมครับ?
Q: ใช่ครับ
A: งั้น คงต้องพึ่งพาคำสั่ง find ครับ เพื่อที่ list เอาเฉพาะไฟล์ทั้งหมดออกมาก่อน เพราะคำสั่ง ls ธรรมดามันจะไล่ไปตาม directory ทีละ directory

เริ่มจาก

$ find /home/user/Documents

มันจะ list ทุกอย่างทั้งไฟล์ และ ไดเรคตอรี่และในไดเรคตอรี่ย่อยออกมา

เราต้องการเฉพาะไฟล์ ระบุ option -type f
เราต้องการให้มันแสดงวันที่ของไฟล์ออกมาด้วย อันนี้ต้องพึ่งคำสั่ง ls โดยใช้ option ของ ls เป็น –full-time

$ find /home/user/Documents -type f -exec ls --full-time {} \;

โดย {} เป็นการระบุว่าให้ find ใช้คำสั่ง ls –full-time กับ output ของ find ส่วน \; เป็นตัวระบุว่า จบ option ของ คำสั่ง find แค่นี้

output ที่ได้ จะเป็นไฟล์ “ทั้งหมด” โดยที่ในแต่ละบรรทัดจะมี ข้อมูลอย่างอื่นของไฟล์นั้นออกมาด้วย เช่น permission, owner, group, size ซึ่งเราไม่สนใจ เราตัดเอาข้อมูลที่อยู่ข้างหน้าเหล่านั้นออกไปได้ โดยใช้คำสั่ง cut โดยในกรณีนี้ใช้ space ‘ ‘ เป็นตัวแบ่ง field และ เอาข้อมูลตั้งแต่ column ที่ 6 เป็นต้นไป

$ find /home/user/Documents -type f -exec ls --full-time {} \; | cut -f6- -d' '

คราวนี้เราก็ได้ไฟล์ทั้งหมดออกมาโดยนำหน้าชื่อไฟล์ด้วยวันที่/เวลา ซึ่งเราสามารถส่งเข้าไป sort โดยให้เรียงจากหลังมาหน้า
sort -r และ เอา output ทั้งหมดมาตัดเอาเฉพาะบรรทัดแรกโดยใช้ คำสั่ง head -1 เหมือนเดิม

$ find /home/user/Documents -type f -exec ls --full-time {} \; cut -f6- -d' ' | sort -r | head -1

ซึ่ง output ที่ได้จากคำสั่ง head อันนี้จะมี วัน/เวลาของไฟล์ นำหน้า ตามด้วยชื่อไฟล์ ซึ่งอาจจะเอาไปใช้งานได้เลย
หรือ ถ้าต้องการเฉพาะชื่อไฟล์ เพื่อจะเอาไปทำอะไรอย่างอื่นต่อ ก็ต้องส่งไปให้คำสั่ง cut เพื่อตัด field ข้อมูลที่อยู่ด้านหน้าออก

ขอบคุณคำถามจาก Garnet Komane ครับ

ปล. สุดท้ายแล้วจากคำสั่งข้างบนที่ว่า แทนที่จะพิมพ์เอาบน command line แล้วไปเปลี่ยน path ที่จะให้ค้นหา เขียนมันใหม่เป็น shell script เลยจะเรียกใช้งานได้ง่ายกว่า ซึ่งจะได้ shell script ประมาณนี้ครับ

#!/bin/bash

LOCATION="$1"

[ -z "$LOCATION" ] && { echo "Usage: $0 LOCATION"; exit; }

FILE=$(
find $LOCATION -type f -exec ls --full-time {} \;  |\
cut -f6- -d' '                                     |\
sort -r                                            |\
head -1                                            |\
cut -f4- -d' '
)

STAMP=$(date -r "$FILE" "+%Y-%m-%d %H:%M:%S")

echo "$STAMP $FILE"

หรือ ดาวน์โหลด script ได้จาก ที่นี่