แก้ไขหรือทางเลือกสำหรับ mktemp ใน OS X


73

ฉันกำลังดูสคริปต์ทุบตีคนอื่นเขียนว่าใช้mktemp:

TEMP=`mktemp --directory`

อย่างไรก็ตามบรรทัดนี้ใช้ไม่ได้กับเครื่องของฉัน (OS X 10.6)

ฉันจะแก้ไขบรรทัดนี้เพื่อให้เข้ากันได้กับ cross-un * x-like-platform ได้อย่างไร แก้ไข:คำสั่งทางเลือกจะเพียงพอเช่นกัน

คำตอบ:


109

ต่อไปนี้เป็นสิ่งที่ฉันใช้เพื่อสร้างไดเรกทอรีชั่วคราวที่ทำงานได้ทั้ง Linux และ Darwin (ทุกรุ่นก่อน Mac OS X 10.11) โดยไม่ต้องใช้ hardcoding $TMPDIRหรือ/tmp:

mytmpdir=`mktemp -d 2>/dev/null || mktemp -d -t 'mytmpdir'`

พื้นหลัง:

คำสั่ง GNU mktemp ไม่จำเป็นต้องมีอาร์กิวเมนต์ ธรรมดาmktempจะทำงานและสร้างไฟล์ชั่วคราวในไดเรกทอรีชั่วคราวของระบบ

ธรรมดาmktemp -dจะสร้างไดเรกทอรีแทนไฟล์ซึ่งเป็นสิ่งที่คุณต้องการใช้บน Linux

(gnu-coreutils)$ man mktemp
> ..
> If DIR is not specified, uses $TMPDIR if set, else /tmp.
> ..

โดยค่าเริ่มต้น GNU mktemp จะใช้แม่แบบtmp.XXXXXXXXXXสำหรับชื่อของไดเรกทอรีย่อย (หรือไฟล์) ในการปรับแต่งเทมเพลตนี้-tสามารถใช้ตัวเลือกได้

mktemp ของ OSX ไม่มีเทมเพลตเริ่มต้นและต้องระบุเทมเพลต น่าเสียดายที่ GNU mktemp ใช้เทมเพลตเป็น-tตัวเลือกใน OSX สิ่งนี้จะถูกส่งเป็นอาร์กิวเมนต์ตำแหน่ง mktemp ของ OSX นั้นมี-tตัวเลือกที่หมายถึงอย่างอื่นแทน -tตัวเลือกใน OSX เป็นเอกสารที่เป็น "คำนำหน้า" สำหรับแม่แบบ มันถูกขยายเป็น{prefix}.XXXXXXXXดังนั้นจึงเพิ่ม Xs ลงไปโดยอัตโนมัติ (เช่นmktemp -d -t exampleสามารถสร้างexample.zEJZWCTQในไดเรกทอรีชั่วคราว)

ฉันรู้สึกประหลาดใจที่จะพบว่าในสภาพแวดล้อมลินุกซ์จำนวนมาก$TMPDIRจะไม่ได้ตั้งค่าเริ่มต้น โปรแกรม CLI หลายคนจะสนับสนุนมันเมื่อตั้ง /tmpแต่ยังคงต้องเริ่มต้นสำหรับ ซึ่งหมายความว่าการส่งผ่าน$TMPDIR/example.XXXXXXXXไปยัง mktemp หรือ mkdir นั้นอันตราย เพราะอาจสร้าง/example.XXXXXXXXในไดเรกทอรีรากของโลคัลดิสก์ (เนื่องจาก $ TMPDIR ถูกยกเลิกการตั้งค่าและกลายเป็นสตริงว่าง)

ใน OSX, $TMPDIRตั้งเสมอและ (อย่างน้อยในเปลือกเริ่มต้น) มันไม่ได้ถูกกำหนด/tmp(ซึ่งเป็น symlink ไป/private/tmp) /var/folders/dx/*****_*************/Tแต่เพื่อ ดังนั้นสิ่งที่เราทำเพื่อ OSX ควรเคารพพฤติกรรมเริ่มต้นนั้น

โดยสรุปสิ่งต่อไปนี้คือสิ่งที่ฉันใช้เพื่อสร้างไดเรกทอรีชั่วคราวที่ทำงานได้ทั้ง Linux และ Darwin (Mac OS X) โดยไม่ต้องใช้ hardcoding $TMPDIRหรือ/tmp:

mytmpdir=`mktemp -d 2>/dev/null || mktemp -d -t 'mytmpdir'`

ส่วนแรกคือสำหรับ Linux คำสั่งนี้จะล้มเหลวในดาร์วิน (Mac OS X) ด้วยรหัสสถานะข้อผิดพลาด1ตอบสนองด้วย "การใช้งาน: ... " นั่นเป็นเหตุผลที่เราไม่สนใจ stderr และดำเนินการแทนตัวแปร Mac mytmpdirคำนำหน้าจะใช้เฉพาะบน Mac (ที่ตัวเลือกที่จะต้องได้รับการตั้งค่า)


12
เจ๋งจริงๆ บางครั้งพฤติกรรมที่แตกต่างของ OS X ก็น่ารำคาญ
therealmarv

6
@therealmarv ฉันอยากจะพูดเสมอ
Nikita Volkov

10
ฉันเพิ่งรันmktemp -dบน OS X 10.11.5 El Capitan และทำงานได้ตามที่คาดไว้file $(mktemp -d):: /var/folders/j4/htlnmbf97vlcdszj7_x8g0vh4k3_fp/T/tmp.JXmsrQnL: directory
Heath Borders

2
อ๋อ ฉันแปลกใจที่คุณเป็นเพียงแค่นี้ Just Worked ™
Heath Borders

1
นอกจากนี้ถ้าคุณรันmktemp -d -t 'mytmpdir'บน Linux (ทดสอบด้วยmktempจากcoreutils 8.26) ก็ทำงานได้ตามที่คาดไว้

15

คุณต้องระบุแม่แบบ mktemp -d /tmp/foo.XXXXควรทำงาน. --directoryผมไม่เคยเห็น การ--แนะนำว่าเป็นส่วนขยายของ GNU


6
หากคุณต้องการที่จะใช้เมื่อมีทำ$TMPDIR mktemp -d "${TMPDIR:-/tmp}"/foo.XXXXใช้งานได้กับทุบตีบน Mac และกดบน Debian ดังนั้นจึงดูเหมือนพกพาได้
Tom Anderson

9

เปลี่ยนไป--directory -dอดีตคือ GNU-ism แต่ GNU mktempจาก coreutils ก็รองรับ-dเช่นกัน mktempใน OS X เป็นเช่นเดียวกับจาก BSD ดังนั้น-dควรจะสวยแบบพกพาในระบบที่จริงจัดส่งmktempโปรแกรม


ฉันเพิ่งลองmktemp -dและมันก็ไม่ทำงานเหมือนกัน
คิด

1
ไคล์มีคำตอบที่สมบูรณ์ mktempบน OS X ต้องใช้แม่แบบ สคริปต์ที่คุณใช้ถือว่าเป็นแบบแผนของ GNU ซึ่งใช้แม่แบบเริ่มต้นหากไม่มีการระบุ
James Sneeringer

ปัญหาคือยูนิกซ์คาดว่าXXXXXจะได้รับการจัดหาในเทมเพลตซึ่ง OS X ไม่แน่ใจว่ามีการตั้งค่าเทมเพลตที่เข้ากันได้หรือไม่?
user3467349

2
mktempบน OS X 10.11.5 El Capitan ใช้ได้สำหรับฉันfile $(mktemp -d)::/var/folders/j4/htlnmbf97vlcdszj7_x8g0vh4k3_fp/T/tmp.JXmsrQnL: directory
Heath Borders

4
temp_dir="$(mktemp -q -d -t "$(basename "$0").XXXXXX")"
  • mktempสำหรับ BSD (รวมถึงOSX ) ต้องใช้เทมเพลต แต่จะอนุญาตให้มีจำนวนXs ใด ๆในเทมเพลต
  • (GNU) mktempสำหรับ Linux ไม่จำเป็นต้องมีเทมเพลตอย่างไรก็ตามหากมีการระบุเทมเพลตดังนั้นจำนวนของXs ต้องเป็น 6

โปรดทราบว่า-tเลิกใช้แล้วสำหรับGNUmktempดังนั้นจะมีรหัสที่สามารถพิสูจน์ได้ในอนาคต

temp_dir="$(mktemp -q -d -t "$(basename "$0").XXXXXX" 2>/dev/null || mktemp -q -d)"
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.