Saya memiliki variabel dalam skrip bash saya yang nilainya seperti ini:
~/a/b/c
Perhatikan bahwa ini adalah tilde yang tidak dikembangkan. Ketika saya melakukan ls -lt pada variabel ini (sebut saja $ VAR), saya tidak mendapatkan direktori seperti itu. Saya ingin membiarkan bash menafsirkan / memperluas variabel ini tanpa menjalankannya. Dengan kata lain, saya ingin bash menjalankan eval tetapi tidak menjalankan perintah yang dievaluasi. Apakah ini mungkin di bash?
Bagaimana saya bisa meneruskan ini ke skrip saya tanpa ekspansi? Saya melewati argumen di sekitarnya dengan tanda kutip ganda.
Coba perintah ini untuk melihat apa yang saya maksud:
ls -lt "~"
Ini persis situasi saya. Saya ingin tilde diperluas. Dengan kata lain, apa yang harus saya ganti dengan sihir untuk membuat kedua perintah ini identik:
ls -lt ~/abc/def/ghi
dan
ls -lt $(magic "~/abc/def/ghi")
Perhatikan bahwa ~ / abc / def / ghi mungkin ada atau tidak ada.
sumber
eval
.foo=~/"$filepath"
ataufoo="$HOME/$filepath"
dir="$(readlink -f "$dir")"
Jawaban:
Karena sifat StackOverflow, saya tidak bisa hanya membuat jawaban ini tidak dapat diterima, tetapi dalam 5 tahun sejak saya memposting ini, ada jawaban yang jauh lebih baik daripada jawaban saya yang dianggap sederhana dan sangat buruk (saya masih muda, jangan bunuh saya).
Solusi lain di utas ini adalah solusi yang lebih aman dan lebih baik. Lebih disukai, saya akan memilih salah satu dari dua ini:
Jawaban asli untuk tujuan bersejarah (tapi tolong jangan gunakan ini)
Jika saya tidak salah,
"~"
tidak akan diperluas dengan skrip bash dengan cara itu karena diperlakukan sebagai string literal"~"
. Anda dapat memaksa ekspansi melaluieval
seperti ini.Atau, gunakan saja
${HOME}
jika Anda ingin direktori home pengguna.sumber
${HOME}
paling menarik. Apakah ada alasan untuk tidak menjadikan ini sebagai rekomendasi utama Anda? Bagaimanapun, terima kasih!eval
adalah saran yang mengerikan, itu benar-benar buruk karena mendapat begitu banyak upvotes. Anda akan mengalami segala macam masalah ketika nilai variabel berisi karakter meta shell.Jika variabel
var
dimasukkan oleh pengguna,eval
sebaiknya tidak digunakan untuk memperluas tilde menggunakanAlasannya adalah: pengguna dapat secara tidak sengaja (atau sengaja) mengetik misalnya
var="$(rm -rf $HOME/)"
dengan kemungkinan konsekuensi yang membahayakan.Cara yang lebih baik (dan lebih aman) adalah dengan menggunakan ekspansi parameter Bash:
sumber
#
di"${var/#\~/$HOME}"
?$var
.\~
melarikan diri~
? (2) Balasan Anda menganggap itu~
adalah karakter pertama di$var
. Bagaimana kita bisa mengabaikan ruang putih terdepan$var
?:
dalam string yang tidak dikutip. Informasi lebih lanjut dalam dokumen . Untuk menghapus spasi putih terdepan, lihat Cara memangkas spasi putih dari variabel Bash?Merencanakan diri saya dari jawaban sebelumnya , untuk melakukan ini dengan kuat tanpa risiko keamanan yang terkait dengan
eval
:...digunakan sebagai...
Sebagai alternatif, pendekatan yang lebih sederhana yang menggunakan
eval
dengan hati-hati:sumber
printf %q
untuk melarikan diri segala sesuatu tetapi tilde, dan kemudian menggunakaneval
tanpa risiko.Cara aman untuk menggunakan eval adalah
"$(printf "~/%q" "$dangerous_path")"
. Perhatikan bahwa spesifik bash.Lihat pertanyaan ini untuk detailnya
Juga, perhatikan bahwa di bawah zsh ini akan sesederhana
echo ${~dangerous_path}
sumber
echo ${~root}
beri saya tidak ada output pada zsh (mac os x)export test="~root/a b"; echo ${~test}
Bagaimana dengan ini:
Atau:
sumber
realpath
perintah dalam C. Misalnya, Anda dapat menghasilkan executablerealpath.exe
menggunakan pesta dan gcc dari baris perintah ini:gcc -o realpath.exe -x c - <<< $'#include <stdlib.h> \n int main(int c,char**v){char p[9999]; realpath(v[1],p); puts(p);}'
. Cheersrealpath ~
->/home/myhome
<workingdir>/~
.Memperluas (no pun intended) pada jawaban birryree dan halloleo: Pendekatan umum adalah menggunakan
eval
, tetapi ia datang dengan beberapa peringatan penting, yaitu spasi dan redirection output (>
) dalam variabel. Sepertinya ini bekerja untuk saya:Cobalah dengan masing-masing argumen berikut:
Penjelasan
${mypath//>}
strip keluar>
karakter yang bisa mengkritik file selamaeval
.eval echo ...
yang dilakukan ekspansi tilde yang sebenarnya-e
argumen adalah untuk mendukung nama file dengan spasi.Mungkin ada solusi yang lebih elegan, tapi ini yang bisa saya lakukan.
sumber
$(rm -rf .)
.>
karakter?Saya percaya ini yang Anda cari
Contoh penggunaan:
sumber
printf %q
tidak luput dari tildes terkemuka - hampir tergoda untuk mengajukan ini sebagai bug, karena ini adalah situasi di mana ia gagal pada tujuan yang dinyatakan. Namun, untuk sementara, panggilan yang bagus!Inilah solusi saya:
sumber
echo
cara yangexpandTilde -n
tidak akan berperilaku seperti yang diharapkan, dan perilaku dengan nama file yang mengandung garis miring terbalik tidak ditentukan oleh POSIX. Lihat pubs.opengroup.org/onlinepubs/009604599/utilities/echo.htmlCukup gunakan
eval
dengan benar: dengan validasi.sumber
printf %q
untuk menghindari hal-hal lebih aman daripada saya percaya kode validasi tulisan tangan tidak memiliki bug .printf
merupakan$PATH
perintah 'd.bash
? Jika demikian,printf
adalah builtin, dan%q
dijamin akan hadir.bash
cukup sebelumnya untuk tahu untuk tidak mempercayainya. coba:x=$(printf \\1); [ -n "$x" ] || echo but its not null!
Berikut adalah fungsi POSIX yang setara dengan jawaban Bash Håkon Hægland
Sunting 2017-12-10: tambahkan
'%s'
per @CharlesDuffy di komentar.sumber
printf '%s\n' "$tilde_less"
mungkin? Kalau tidak, itu akan berperilaku salah jika nama file yang diperluas mengandung garis miring terbalik%s
,, atau sintaksis lain yang bermakna bagiprintf
. Selain itu, meskipun, ini adalah jawaban yang bagus - benar (ketika ekstensi bash / ksh tidak perlu dibahas), jelas aman (tidak mucking denganeval
) dan singkat.mengapa tidak menggali langsung ke direktori home pengguna dengan getent?
sumber
Hanya untuk memperpanjang jawaban birryree untuk jalur dengan spasi: Anda tidak dapat menggunakan
eval
perintah apa adanya karena memisahkan evaluasi dengan spasi. Salah satu solusinya adalah mengganti spasi sementara untuk perintah eval:Contoh ini tentu saja bergantung pada asumsi yang
mypath
tidak pernah berisi urutan char"_spc_"
.sumber
$(rm -rf .)
Anda mungkin menemukan ini lebih mudah dilakukan dengan python.
(1) Dari baris perintah unix:
Hasil dalam:
(2) Dalam skrip bash sebagai satu kali - simpan ini sebagai
test.sh
:Menjalankan
bash ./test.sh
hasil dalam:(3) Sebagai utilitas - simpan ini di
expanduser
suatu tempat di jalur Anda, dengan menjalankan izin:Ini kemudian dapat digunakan pada baris perintah:
Atau dalam naskah:
sumber
echo $thepath
buggy; perlu untukecho "$thepath"
memperbaiki kasus-kasus yang kurang umum (nama dengan tab atau run spasi dikonversi menjadi spasi tunggal; nama dengan gumpalan diperluas), atauprintf '%s\n' "$thepath"
untuk memperbaiki yang tidak umum juga (mis. file bernama-n
, atau file dengan backslash literals pada sistem yang sesuai dengan XSI). Demikian pula,thepath=$(expanduser "$1")
echo
untuk berperilaku dengan cara yang sepenuhnya ditentukan oleh implementasi jika ada argumen yang mengandung backslash; ekstensi XSI opsional untuk POSIX mengamanatkan perilaku ekspansi default (tidak-e
atau-E
diperlukan) untuk nama-nama tersebut.Sederhana : ganti 'ajaib' dengan 'eval echo'.
Masalah: Anda akan mengalami masalah dengan variabel lain karena eval itu jahat. Misalnya:
Perhatikan bahwa masalah injeksi tidak terjadi pada ekspansi pertama. Jadi jika Anda hanya menggantinya
magic
denganeval echo
, Anda harus baik-baik saja. Tetapi jika Anda melakukannyaecho $(eval echo ~)
, itu akan rentan terhadap injeksi.Demikian pula, jika Anda melakukannya
eval echo ~
bukaneval echo "~"
, itu akan dihitung sebagai dua kali diperluas dan oleh karena itu injeksi akan segera mungkin dilakukan.sumber
s='echo; EVIL_COMMAND'
. (Ini akan gagal karenaEVIL_COMMAND
tidak ada di komputer Anda. Tetapi jika perintah iturm -r ~
misalnya, itu akan menghapus direktori home Anda.)Saya telah melakukan ini dengan substitusi parameter variabel setelah membaca di jalan menggunakan read -e (antara lain). Jadi pengguna dapat melakukan tab-melengkapi path, dan jika pengguna memasukkan ~ path itu akan diurutkan.
Manfaat tambahan adalah bahwa jika tidak ada tilde tidak ada yang terjadi pada variabel, dan jika ada tilde tetapi tidak di posisi pertama itu juga diabaikan.
(Saya menyertakan -i untuk dibaca karena saya menggunakan ini dalam satu lingkaran sehingga pengguna dapat memperbaiki jalur jika ada masalah.)
sumber