ทำการทดสอบ -nt / -ot ใน POSIX sh


11

บิวด์อินtestและ[ยูทิลิตีมีการทดสอบ-nt("ใหม่กว่า") และ-ot("เก่ากว่า") ในเชลล์ส่วนใหญ่แม้ว่าเชลล์จะทำงานใน "โหมด POSIX" (เช่นเดียวกับยูทิลิตี้ภายนอกของชื่อเดียวกันบน ระบบที่ฉันสามารถเข้าถึงได้) การทดสอบเหล่านี้ใช้สำหรับการเปรียบเทียบการประทับเวลาการปรับเปลี่ยนในสองไฟล์ เอกสารความหมายของพวกเขาจะแตกต่างกันเล็กน้อยในการใช้งาน (โดยคำนึงถึงสิ่งที่เกิดขึ้นหากไฟล์หนึ่งหรือไฟล์อื่นที่ไม่ได้อยู่) แต่พวกเขาจะไม่รวมอยู่ในข้อมูลจำเพาะ POSIX สำหรับtestยูทิลิตี้

พวกเขาจะไม่ถูกพาไปข้างหน้าในtestยูทิลิตี้เมื่อคำสั่งแบบมีเงื่อนไขถูกลบออกจากเปลือก [KornShell] เพราะพวกเขาไม่ได้รวมอยู่ในtestยูทิลิตี้ที่มีอยู่ในการติดตั้งในอดีตของshยูทิลิตี้

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

if [ "$sigfile"     -nt "$timestamp" ] ||
   [ "$sigfile.tmp" -nt "$timestamp" ]
then
    return
fi

... ยูทิลิตี้อื่น ๆ ที่ฉันสามารถใช้นอกเหนือจากmake(ซึ่งจะทำให้สคริปต์ที่เหลือไม่ได้พูดอย่างน้อยที่สุด) หรือฉันควรจะสมมติว่าไม่มีใครที่จะเรียกใช้สคริปต์ใน "การดำเนินการทางประวัติศาสตร์ของsh" หรือลาออกเพื่อเขียนเปลือกเฉพาะเช่นbash?


อย่างที่คุณเห็นในคำตอบของฉันทุบตีไม่ได้ใช้-ntคุณสมบัติของtestในลักษณะที่คาดว่าตั้งแต่ประมาณ 1995. คุณควรใช้findนิพจน์ basd แม้ว่าbashคุณจะชอบพฤติกรรมที่ถูกต้องก็ตาม
schily

คำตอบ:


10

POSIXLY:

f1=/path/to/file_1
f2=/path/to/file_2

if [ -n "$(find -L "$f1" -prune -newer "$f2")" ]; then
    printf '%s is newer than %s\n' "$f1" "$f2"
fi

การใช้พา ธ สัมบูรณ์ไปยังไฟล์จะป้องกันการบวกผิดด้วยชื่อไฟล์ที่มีการขึ้นบรรทัดใหม่เท่านั้น

ในกรณีที่ใช้เส้นทางสัมพัทธ์ให้เปลี่ยนfindคำสั่งเป็น:

find -L "$f1" -prune -newer "$f2" -exec echo . \;

ในทางเทคนิคแล้วฉันคิดว่ามันจะล้มเหลวหาก$f1มีเพียงการขึ้นบรรทัดใหม่;)
ilkkachu

1
@ilkkachu สามารถแก้ไขได้ด้วย-exec echo x \;หรือคล้ายกัน?
muru

@muru ใช่ -printfจะง่ายถ้าเป็นมาตรฐาน
ilkkachu

3
@Kusalananda AFAICT findสถานะการออกเป็นอิสระจากสิ่งที่แต่ละการทดสอบfindกลับมา - ยกเว้นบางทีหากมีข้อผิดพลาดในการใช้การทดสอบเหล่านั้น findออกจาก 0 แม้ว่าจะไม่พบไฟล์ใด ๆ
muru

1
โปรดทราบว่าพฤติกรรมของ[ / -nt /nofile ]แตกต่างกันไปตามการใช้งาน (แต่ไม่เคยส่งข้อผิดพลาดใด ๆ )
Stéphane Chazelas

7

ซึ่งอาจเป็นกรณีสำหรับการใช้หนึ่งในคำสั่ง Unix lsที่เก่าแก่ที่สุดที่

x=$(ls -tdL -- "$a" "$b")
[ "$x" = "$a
$b" ]

ผลลัพธ์จะเป็นจริงถ้า a ใหม่กว่า b


3
ไม่สามารถใช้งานได้หากชื่อไฟล์ขึ้นต้นด้วย-(หายไป--) คุณจะต้องให้มันเทียบเท่ากับ-L -ntที่ไม่ทำงานเพื่อเปรียบเทียบxและ$'x\nx'เช่น
Stéphane Chazelas

1
จี๊ด! แต่ยังไงเหรอ
Kusalananda

4

คุณตั้งคำถามที่น่าสนใจและทำการอ้างสิทธิ์ที่ควรได้รับการยืนยันก่อน

ฉันตรวจสอบพฤติกรรมของ:

$shell -c '[ Makefile -nt SCCS/s.Makefile ] && echo newer'

กับเปลือกหอยต่าง ๆ นี่คือผลลัพธ์:

  • bashไม่ทำงาน - ไม่พิมพ์งานใด ๆ

  • เรื่องเหลวไหล งาน

  • เส้นประไม่ทำงาน - พิมพ์อะไรไม่ได้

  • ksh88ไม่ทำงาน - ไม่พิมพ์อะไรเลย

  • ksh93 ทำงานได้

  • mkshไม่ทำงาน - ไม่พิมพ์อะไรเลย

  • print posh : posh: [: -nt: ผู้ควบคุม / operand ที่ไม่คาดคิด

  • yash ใช้ งานได้

  • zsh ทำงานในรุ่นที่ใหม่กว่ารุ่นเก่ากว่าไม่พิมพ์

ดังนั้นสี่เก้าเชลล์จึงสนับสนุนคุณสมบัติ-ntและใช้อย่างถูกต้อง ได้อย่างถูกต้องในกรณีนี้หมายถึง: สามารถที่จะเปรียบเทียบเวลาประทับบนแพลตฟอร์มล่าสุดที่เวลาการสนับสนุนย่อยสองแสตมป์เมล็ด โปรดทราบว่าไฟล์ที่ฉันเลือกแตกต่างกันโดยทั่วไปเพียงไม่กี่ไมโครวินาทีในการประทับเวลา

เนื่องจากง่ายต่อการค้นหาfindการนำไปใช้งานฉันแนะนำให้เปลี่ยน

if [ "$file1" -nt "$file2" ] ; then
    echo newer
fi

โดยการfindแสดงออกตาม

if [ "$( find "$file1" -newer "$file2" )" ]; then
    echo newer
fi

ทำงานอย่างน้อยตราบ$file1ใดที่ไม่เพียงมีการขึ้นบรรทัดใหม่

if [ "$( find -L "$file1" -newer "$file2" -exec echo newer \; )" ]; then
    echo newer
fi

ช้าลงเล็กน้อย แต่ทำงานได้อย่างถูกต้อง

BTW: เกี่ยวกับการทำให้ฉันไม่สามารถพูดได้สำหรับการใช้งานทั้งหมด แต่SunPro Makeสนับสนุนการเปรียบเทียบเวลากับระดับนาโนวินาทีตั้งแต่ประมาณ 20 ปีในขณะที่smakeและgmakeเพิ่มคุณสมบัตินี้เมื่อเร็ว ๆ นี้


1
การทดสอบ "ไม่ทำงาน" ไม่ทำงานเนื่องจากความล้มเหลวในการเปรียบเทียบการประทับเวลาย่อยที่สอง (แน่นอนหรือไม่) หรืออย่างอื่นใช่ไหม การประทับเวลาจริงของไฟล์ที่เกี่ยวข้องกับการทดสอบของคุณคืออะไร +1 สำหรับการทดสอบ!
Kusalananda

2
ฉันคิดว่าการลงคะแนนเสียงอาจเกี่ยวกับถ้อยคำที่ใช้ในการเผชิญหน้า นี่มันยุติธรรมกว่าที่จะเรียกว่าข้อ จำกัด (มีความหมายในบางบริบท) findการใช้งานบางอย่างเช่น busybox หรือเครื่องมือมรดกจะมีข้อ จำกัด เดียวกัน
Stéphane Chazelas

3
คุณจะต้อง-Lสำหรับการรุ่นที่จะเทียบเท่ากับfind -ntนอกจากนี้ยังจะล้มเหลวในชื่อไฟล์ที่เริ่มต้นด้วย-หรือ!, (...
Stéphane Chazelas

2
ตามความเป็นจริงฉันมักจะได้ลงคะแนนเมื่อฉันใช้ถ้อยคำที่คาดคั้น ที่นี่จะช่วยได้หากคุณระบุบริบท (ไฟล์ที่แก้ไขภายในเวลาประทับเดียวกันเมื่อตัดปลายเป็นความละเอียดที่สอง) ในตอนเริ่มต้นของคำตอบ
Stéphane Chazelas

1
@ schily ใช่findมีBSDs find -f "$file"แต่มันไม่ได้พกพา
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.