Bagaimana saya bisa mengambil nama file absolut dalam skrip shell di Mac OS X?

19

Saya ingin mengambil nama file absolut dari file skrip yang saat ini dieksekusi. Tautan juga harus dipecahkan.

Di Linux, ini sepertinya dilakukan seperti ini:

$(readlink -mn "$0")

tetapi readlinktampaknya bekerja sangat berbeda pada Mac OS X.

Saya sudah membaca bahwa ini dilakukan dengan menggunakan

$(realpath $0)

di BSD tapi itu tidak berhasil, baik. Mac OS X tidak punya realpath.

Ada ide?

Huxi
sumber
1
Lihat pertanyaan ini di SO: stackoverflow.com/questions/799679/…
Telemakus
3
Dan yang ini: stackoverflow.com/questions/1055671/…
Telemachus
Pilihan lainnya: stackoverflow.com/questions/7665/…
Gerhard Burger

Jawaban:

19

Saya curang dan menggunakan perl untuk hal ini:

#!/bin/bash
dirname=`perl -e 'use Cwd "abs_path";print abs_path(shift)' $0`
echo $dirname

Anda akan berpikir saya hanya akan menulis seluruh skrip dalam perl, dan sering saya lakukan, tetapi tidak selalu.

ericslaw
sumber
Ini berhasil, terima kasih banyak. Saya akan memberi Anda upvote sesegera mungkin. Adakah yang punya cara "kulit murni" untuk melakukan ini?
Huxi
1
Saya khawatir ini sebagus yang didapat. (Mengingat banyak multiple-line "shell murni" hacks satu dapat menemukan di Google.)
Arjan
kemungkinan lain (meskipun jelek) adalah untuk melintasi jalur '..', menghafal (melalui rekursi atau array) hingga '..' mengembalikan file yang sama seperti yang baru saja Anda miliki (yaitu: Anda berada di atas), lalu kembali menyusun jalan saat Anda pergi. Saya telah melihat perangkat lunak cadangan Networker milik Legato melakukan ini selama strace sebagai metode untuk memperoleh jalur 'benar' (tapi mungkin tidak mutlak). Tetapi akan lebih banyak kode daripada yang di atas.
ericslaw
Tidak yakin mengapa seseorang memodifikasi kode untuk menggunakan $ 1, bukan $ 0. Bukankah $ 1 arg pertama ke skrip bash? Saya ingin jalan ke skrip bash yang mengeksekusi, bukan argumen pertama.
ericslaw
27
#!/usr/bin/env bash
scriptDir="$(cd "$(dirname "$0")" && pwd -P)"
jhclark
sumber
Bekerja di MacOSX juga.
Alexar
1
Ini super! Ada banyak jawaban rumit lain yang beredar.
Jason S
3
Ini hanya berfungsi untuk file dalam direktori yang disinkronkan, bukan untuk file yang disinkronkan secara umum
Gerhard Burger
1
Penting juga untuk melakukan unset -v CDPATHsebelum cd karena cd dapat menyebabkan output yang tidak diinginkan jika CDPATH diatur.
Binary Phile
Untuk menangani setidaknya satu lapisan symlinking file, Anda juga dapat menguji dengan cara yang kompatibel dengan readlink (mac tidak punya -f): scriptDir=$(unset -v CDPATH; cd "$(dirname "$(readlink "$BASH_SOURCE" || echo "$BASH_SOURCE)")" && pwd -P)
Binary Phile
0

Ini menangani kombo symlink, dan ini berfungsi pada file dan folder:

#!/usr/bin/env bash
realpath()
{
    if ! pushd $1 &> /dev/null; then 
        pushd ${1##*/} &> /dev/null
        echo $( pwd -P )/${1%/*}
    else
        pwd -P
    fi
    popd > /dev/null
}

Tetapi itu tidak mendukung realpath - relatif-untuk. Ini membutuhkan konversi yang dijelaskan di sini .

Oliver
sumber
0

Pendekatan lain:

# Install.
brew install coreutils

# Use the GNU variant.
grealpath --help
FMc
sumber