Dengan skrip di bawah ini, bagaimana saya bisa memastikan bahwa argumen tersebut hanya berisi nama file yang valid di dalam /home/charlesingalls/
dan bukan path ( ../home/carolineingalls/
) atau wildcard, dll?
Saya hanya ingin skrip dapat menghapus satu file dari direktori hard-coded yang diberikan. Skrip ini akan berjalan sebagai pengguna istimewa.
#!/bin/bash
rm -f /home/charlesingalls/"$1"
/
. Wildcard tidak ditafsirkan dalam kutipan.-r
denganrm
.rm -r
adalah untuk penghapusan secara rekursif dari suatu direktori dan semua file dan direktori di bawahnya. Ini hanya berguna saat menghapus direktori. Lebih umum, jangan pemujaan kargo. yaitu jangan hanya menyalin hal-hal yang terlihat berguna ke dalam baris perintah atau skrip Anda tanpa memahami apa yang mereka lakukan atau bagaimana mereka bekerja Dewa pesawat yang membawa kargo ajaib bisa marah dan menghapus semua file Anda.Jawaban:
Jika Anda hanya ingin menghapus file di
/home/charlesingalls
(dan bukan file di subdirektori) maka mudah: cukup periksa bahwa argumennya tidak mengandung a/
.Ini berjalan
rm
bahkan jika argumennya adalah.
atau..
atau kosong, tetapi dalam kasus iturm
akan gagal menghapus direktori.Wildcard tidak relevan di sini karena tidak ada ekspansi wildcard yang dilakukan.
Ini aman bahkan di hadapan tautan simbolik: jika file tersebut adalah tautan simbolik, symlink (yang ada di dalam
/home/charlesingalls
) akan dihapus, dan target tautan itu tidak terpengaruh.Perhatikan bahwa ini mengasumsikan bahwa
/home/charlesingalls
tidak dapat dipindahkan atau diubah. Itu seharusnya ok jika direktori tersebut dikodekan dalam skrip, tetapi jika itu ditentukan dari variabel maka penentuan mungkin tidak lagi valid pada saatrm
perintah dijalankan.Berdasarkan informasi tambahan bahwa argumen tersebut adalah nama host virtual, Anda harus melakukan daftar putih daripada daftar hitam: periksa bahwa nama tersebut adalah nama host virtual yang masuk akal, bukan hanya melarang garis miring. Saya memeriksa apakah namanya dimulai dengan huruf kecil atau digit dan tidak mengandung karakter selain huruf kecil, digit, titik dan garis.
sumber
.
Jawaban ini mengasumsikan bahwa
$1
diizinkan untuk memasukkan subdirektori. Jika Anda tertarik pada kasus yang lebih sederhana di mana$1
seharusnya menjadi nama direktori sederhana, maka lihat salah satu jawaban lainnya.Wildcard tidak diperluas ketika dalam tanda kutip ganda. Karena
$1
dalam tanda kutip ganda, wildcard tidak menjadi masalah.Keduanya
../
dan symlink dapat mengaburkan lokasi sebenarnya dari suatu file. Yang ditunjukkan di bawah ini adalah tes untuk menentukan apakah file tersebut benar-benar, tidak hanya tampaknya, di bawah jalur yang kita inginkan.Sistem yang lebih baru: menggunakan
realpath
Adapun untuk mengetahui apakah file tersebut benar-benar jika file tersebut benar-benar di bawah
/home/charlesingalls/
atau tidak, Anda dapat menggunakanrealpath
:Di atas berjalan
exit 1
jika file yang ditentukan oleh$1
mana saja selain di bawah direktori/home/charlesingalls/
.realpath
mengkanonik seluruh jalur, menghilangkan symlink dan../
.realpath
adalah bagian dari GNU coreutils dan harus tersedia di sistem Linux apa pun.realpath
membutuhkan GNU coreutils 8.15 (Jan 2012) atau lebih baik .Contohnya
Untuk mendemonstrasikan bagaimana realpath mengikuti
../
untuk menentukan lokasi sebenarnya dari suatu file (misalnya,-q
opsi untuk grep dihilangkan sehingga output aktual dari grep terlihat):Untuk mendemonstrasikan cara mengikuti symlinks:
Sistem yang lebih lama: menggunakan
readlink -e
readlink
juga mampu mengkononisasi jalur, mengikuti kedua symlinks dan../
:Menggunakan contoh file yang sama:
Selain tersedia di sistem GNU yang lebih lama, versi
readlink
tersedia di BSD.sumber
coreutils
tidak memilikirealpath
-f
("semua kecuali komponen terakhir harus ada") dan contoh-contohnya menggunakan-e
("semua komponen harus ada"), yang agak membingungkan.rm
bertindak berdasarkan argumen itu sendiri, bukan targetnya.grep -q
untuk menjaga agar tidakgrep
menghasilkan garis yang cocok. Anda masih mendapatkan status keluar begitu&&
dan||
masih berfungsi persis seperti dulu.Jika Anda ingin melarang path sepenuhnya, cara paling sederhana adalah dengan menguji apakah variabel berisi slash (
/
). Dalam bash:Ini akan memblokir semua jalur, termasuk
foo/bar
. Anda bisa menguji..
, tetapi itu akan meninggalkan kemungkinan symlink menunjuk ke direktori di luar jalur target.Jika Anda hanya ingin mengizinkan penghapusan satu file, saya tidak berpikir Anda harus menggunakan
rm -r
.Juga, tergantung pada apa yang Anda lakukan, Anda bisa menggunakan izin file sistem untuk hanya mengizinkan menghapus file yang bisa dihapus sendiri oleh pengguna. Sesuatu seperti ini:
Meskipun seperti yang dikomentari @Gilles, ini memiliki masalah kutipan: ia akan gagal jika
$1
berisi satu kutipan, jadi variabel harus diuji terlebih dahulu (dengan misalnyaif [[ "$1" = *\'* ]] ; then fail...
atau lebih dengan memasukkan daftar karakter yang masuk akal), atau nama file dilewatkan variabel lingkungan dengan missumber
su
perintah Anda rusak karena penawaran salah. Anda menjalankan perintah dengan argumen yang diinterpolasi sebagai cuplikan shell. Misal jika argumennya$(touch foo)
maka kode Anda berjalantouch foo
.'
dengan'\''
) atau meneruskannya melalui saluran lain seperti variabel lingkungan (yang akan saya lakukan di sinifile_to_remove="$1" su -c 'rm "/home/charlesingalls/$file_to_remove"'
:). Ternyata nama file itu seharusnya nama host virtual, jadi menolak semua karakter khusus juga akan baik-baik saja di sini.