Perbaiki atau alternatif untuk mktemp di OS X

73

Saya melihat skrip bash yang ditulis oleh orang lain yang menggunakan mktemp:

TEMP=`mktemp --directory`

Namun, baris ini tidak berfungsi pada mesin saya (OS X 10.6).

Bagaimana cara saya memperbaiki baris ini sehingga kompatibel dengan cross-un * x-like-platform? EDIT: Perintah alternatif juga cukup.

mindeavor.
sumber

Jawaban:

109

Berikut ini adalah apa yang akhirnya saya gunakan untuk secara andal membuat direktori sementara yang berfungsi pada Linux dan Darwin (semua versi sebelum Mac OS X 10.11), tanpa hardcoding $TMPDIRatau /tmp:

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

Latar Belakang:

Perintah mktemp GNU tidak membutuhkan argumen. Plain mktempakan bekerja dan membuat file sementara di direktori sementara sistem.

Plain mktemp -dakan membuat direktori alih-alih file, yang ingin Anda gunakan di Linux.

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

Secara default, mktemp GNU menggunakan templat tmp.XXXXXXXXXXuntuk nama sub direktori (atau file). Untuk menyesuaikan template ini, -topsi dapat digunakan.

Mktemp OSX tidak memiliki templat default dan mengharuskan templat ditentukan. Sayangnya, ketika GNU mktemp mengambil templat sebagai -topsi, pada OSX ini dilewatkan sebagai argumen posisi. Sebaliknya, mktemp OSX memiliki -topsi yang berarti sesuatu yang lain. The -tpilihan pada OSX didokumentasikan sebagai "awalan" untuk template. Ini diperluas ke {prefix}.XXXXXXXX, jadi itu menambahkan Xs ke secara otomatis (misalnya mktemp -d -t exampledapat membuat example.zEJZWCTQdi direktori temp).

Saya terkejut menemukan bahwa di banyak lingkungan Linux, $TMPDIRyang tidak diatur secara default. Banyak program CLI yang mendukungnya ketika diatur, tetapi masih membutuhkan default untuk itu /tmp. Ini berarti meneruskan $TMPDIR/example.XXXXXXXXke mktemp atau mkdir berbahaya karena dapat menghasilkan /example.XXXXXXXXdi direktori root disk lokal (karena $ TMPDIR tidak disetel dan menjadi string kosong).

Pada OSX, $TMPDIRselalu diatur dan (setidaknya di shell default) tidak diatur ke /tmp(yang merupakan symlink ke /private/tmp) tetapi ke /var/folders/dx/*****_*************/T. Jadi apa pun yang kita lakukan untuk OSX, harus menghormati perilaku default itu.

Sebagai kesimpulan, berikut ini adalah apa yang akhirnya saya gunakan untuk membuat direktori sementara yang berfungsi baik pada Linux dan Darwin (Mac OS X), tanpa hardcoding, salah satu $TMPDIRatau /tmp:

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

Bagian pertama adalah untuk Linux. Perintah ini akan gagal pada Darwin (Mac OS X) dengan kode status kesalahan 1merespons dengan "penggunaan: ...". Itu sebabnya kami mengabaikan stderr dan malah menjalankan varian Mac. The mytmpdirprefix hanya digunakan pada Mac (di mana opsi yang diperlukan untuk mengatur).

Timo Tijhof
sumber
12
Benar-benar keren. Terkadang perilaku yang berbeda pada OS X menjengkelkan.
therealmarv
6
@therealmarv Saya lebih suka mengatakan, selalu.
Nikita Volkov
10
Saya baru saja berlari mktemp -dpada OS X 10.11.5 El Capitan, dan itu bekerja seperti yang diharapkan file $(mktemp -d):: /var/folders/j4/htlnmbf97vlcdszj7_x8g0vh4k3_fp/T/tmp.JXmsrQnL: directory
Perbatasan Heath
2
Ya. Saya terkejut ketika Anda mengetahui bahwa Just Worked ™ ini.
Perbatasan Heath
1
Juga jika Anda menjalankan mktemp -d -t 'mytmpdir'di Linux (diuji dengan mktempdari coreutils 8.26), itu berfungsi seperti yang diharapkan.
15

Anda harus menyediakan templat. mktemp -d /tmp/foo.XXXXharus bekerja. Saya belum pernah melihatnya --directory. Yang --menunjukkan bahwa itu adalah ekstensi GNU.

Kyle Jones
sumber
6
Jika Anda ingin menggunakan $TMPDIRsaat tersedia, lakukan mktemp -d "${TMPDIR:-/tmp}"/foo.XXXX. Itu bekerja di bash di Mac dan lari di Debian, jadi sepertinya portabel.
Tom Anderson
9

Ubah --directoryke -d. Yang pertama adalah GNU-isme, tetapi GNU mktempdari coreutils juga mendukung -d. The mktempdi OS X adalah sama dengan dari BSD, sehingga -dharus cukup portabel di antara sistem yang benar-benar kapal mktempProgram.

James Sneeringer
sumber
Saya baru saja mencoba mktemp -d, dan tidak berhasil juga.
mindeavor.
1
Kyle memiliki jawaban yang lengkap. Pada mktempOS X memerlukan templat. Skrip yang Anda gunakan mengasumsikan konvensi GNU, yang menggunakan templat default jika tidak ada yang disediakan.
James Sneeringer
Masalahnya adalah bahwa unix mengharapkan XXXXXuntuk disediakan dalam template sedangkan OS X tidak yakin apakah ada flag template yang kompatibel?
user3467349
2
mktemppada OS X 10.11.5 El Capitan bekerja untuk saya file $(mktemp -d)::/var/folders/j4/htlnmbf97vlcdszj7_x8g0vh4k3_fp/T/tmp.JXmsrQnL: directory
Perbatasan Heath
4
temp_dir="$(mktemp -q -d -t "$(basename "$0").XXXXXX")"
  • mktempuntuk BSD (termasuk OSX ) memerlukan templat, tetapi ini memungkinkan sejumlah Xs dalam templat.
  • (GNU) mktempuntuk Linux tidak memerlukan templat, namun, jika templat ditentukan, maka jumlah Xs harus 6.

Catatan yang -tsudah usang untuk GNUmktemp , jadi kode yang lebih tahan akan masa depan

temp_dir="$(mktemp -q -d -t "$(basename "$0").XXXXXX" 2>/dev/null || mktemp -q -d)"
go2null
sumber