Saya memiliki persyaratan, jika saya menjalankan skrip ./123
dengan argumen path kosong, katakan /usr/share/linux-headers-3.16.0-34-generic/.tmp_versions
(direktori ini kosong). Seharusnya menampilkan "direktori kosong"
Kode saya adalah:
#!/bin/bash
dir="$1"
if [ $# -ne 1 ]
then
echo "please pass arguments"
exit
fi
if [ -e $dir ]
then
printf "minimum file size: %s\n\t%s\n" \
$(du $dir -hab | sort -n -r | tail -1)
printf "maximum file size: %s\n\t%s\n" \
$(du $dir -ab | sort -n | tail -1)
printf "average file size: %s"
du $dir -sk | awk '{s+=$1}END{print s/NR}'
else
echo " directory doesn't exists"
fi
if [ -d "ls -A $dir" ]
then
echo " directory is empty"
fi
Saya memiliki tampilan kesalahan seperti, jika saya menjalankan nama skrip ./123 /usr/src/linux-headers-3.16.0-34-generic/.tmp_versions
(direktori ini kosong).
minimum file size: 4096
/usr/src/linux-headers-3.16.0-34-generic/.tmp_versions
maximum file size: 4096
/usr/src/linux-headers-3.16.0-34-generic/.tmp_versions
average file size: 4
alih-alih hanya menampilkan keluaran "direktori kosong" yang menunjukkan keluaran di atas
Output di bawah ini harus ditampilkan jika saya menampilkan skrip dengan argumen yang benar (maksud saya dengan jalur direktori yang benar). mengatakan./123 /usr/share
minimum file size: 196
/usr/share
maximum file size: 14096
/usr/share
average file size: 4000
output yang saya harapkan adalah: ./123 /usr/src/linux-headers-3.16.0-34-generic/.tmp_versions
directory is empty.
shell-script
buddha sreekanth
sumber
sumber
Jawaban:
Di atas adalah tes yang kompatibel dengan POSIX - dan harus sangat cepat.
ls
akan mencantumkan semua file / direktori dalam direktori kecuali.
dan..
masing - masing per baris dan akan-q
mencatat semua karakter yang tidak dapat dicetak (untuk memasukkan\n
baris baru) dalam output dengan?
tanda tanya. Dengan cara ini jikagrep
menerima bahkan satu karakter dalam input itu akan mengembalikan true - else false.Untuk melakukannya dalam shell POSIX saja:
Sebuah POSIX-shell (yang memiliki tidak lebih awal dinonaktifkan
-f
generasi ilename) akanset
dengan"$@"
posisi-parameter array ke salah satu string literal diikuti olehset
perintah di atas, atau yang lain untuk bidang yang dihasilkan oleh operator gumpal pada akhir masing-masing. Apakah itu tergantung pada apakah gumpalan benar-benar cocok dengan sesuatu. Dalam beberapa shell, Anda dapat menginstruksikan glob yang tidak menyelesaikan untuk memperluas ke null - atau tidak sama sekali. Ini kadang-kadang bisa bermanfaat, tetapi tidak portabel dan sering disertai dengan masalah tambahan - seperti harus mengatur opsi shell khusus dan kemudian menghapusnya.Satu-satunya cara portabel untuk menangani argumen bernilai nol melibatkan variabel kosong atau tidak disetel atau
~
ekspansi tilde. Dan yang terakhir, omong-omong, jauh lebih aman daripada yang pertama.Di atas shell hanya menguji salah satu file untuk
-e
xistence jika tidak satu pun dari tiga gumpalan yang ditentukan menyelesaikan lebih dari satu pertandingan. Jadifor
loop hanya dijalankan sama sekali untuk tiga atau lebih sedikit iterasi, dan hanya dalam kasus direktori kosong, atau dalam kasus satu atau lebih pola hanya terpecahkan untuk satu file. Thefor
jugabreak
s jika salah satu gumpalan mewakili file yang sebenarnya - dan seperti yang saya telah mengatur gumpalan di urutan paling mungkin untuk paling tidak mungkin, harus cukup banyak berhenti pada iterasi pertama setiap kali.Apa pun yang Anda lakukan, itu harus melibatkan hanya satu
stat()
panggilan sistem - shell danls
harus keduanya hanya perlu kestat()
direktori yang ditanyai dan daftar file-file laporan giginya yang dikandungnya. Ini kontras dengan perilakufind
yang sebaliknya akanstat()
setiap file Anda mungkin daftar dengan itu.sumber
ls
kasus ini. gumpal dan[
diam ketika mereka tidak memiliki akses. Sebagai contoh,[ -e /var/spool/cron/crontabs/stephane ]
diam-diam akan melaporkan palsu, sementara ada file dengan nama itu.Dengan GNU atau BSD modern
find
, Anda dapat melakukan:(mengasumsikan
$dir
tidak terlihat seperti sebuahfind
predikat (!
,(
,-name...
).POSIXly:
sumber
[-z $dir ]
mengeluh bahwa tidak ada perintah yang dipanggil[-z
pada kebanyakan sistem. Anda membutuhkan ruang di sekitar tanda kurung .[ -z $dir ]
kebetulan benar jikadir
kosong, dan salah untuk sebagian besar nilai laindir
, tetapi tidak dapat diandalkan, misalnya benar jika nilaidir
adalah= -z
atau-o -o -n -n
. Selalu gunakan tanda kutip ganda di sekitar substitusi perintah (ini berlaku juga untuk seluruh skrip Anda).[ -z "$dir" ]
menguji apakah nilai variabeldir
kosong. Nilai variabel adalah string, yang merupakan jalur ke direktori. Itu tidak memberi tahu Anda apa pun tentang direktori itu sendiri.Tidak ada operator untuk menguji apakah direktori kosong, seperti ada untuk file biasa (
[ -s "$dir" ]
berlaku untuk direktori bahkan jika itu kosong). Cara sederhana untuk menguji apakah direktori kosong adalah dengan membuat daftar isinya; jika Anda mendapatkan teks kosong, direktori tersebut kosong.Pada sistem lama yang tidak memiliki
ls -A
, Anda dapat menggunakanls -a
, tetapi kemudian.
dan..
terdaftar.(Jangan membuat indentasi baris yang dimulai
..
karena string harus berisi hanya baris baru, bukan baris baru dan ruang tambahan.)sumber
$(…)
adalah pengganti perintahAnda sedang melihat atribut direktori itu sendiri.
Anda ingin menghitung berapa banyak file di sana:
Jadi, tes untuk "direktori kosong" adalah:
Seperti ini:
sumber
Jawaban tldr saya adalah:
Ini sesuai dengan POSIX dan, tidak terlalu penting, biasanya lebih cepat daripada solusi yang mencantumkan direktori dan menyalurkan output ke grep.
Pemakaian:
Saya suka jawabannya https://unix.stackexchange.com/a/202276/160204 , yang saya tulis ulang sebagai:
Ini daftar direktori dan pipa hasilnya ke grep. Sebagai gantinya, saya mengusulkan fungsi sederhana yang didasarkan pada ekspansi dan perbandingan glob.
Fungsi ini bukan POSIX standar dan memanggil subkulit dengan
$()
. Saya menjelaskan fungsi sederhana ini terlebih dahulu sehingga kita dapat lebih memahami solusi akhir (lihat jawaban tldr di atas) nanti.Penjelasan:
Sisi kiri (LHS) kosong ketika tidak ada ekspansi, yang merupakan kasus ketika direktori kosong. Opsi nullglob diperlukan karena jika tidak ada kecocokan, glob itu sendiri adalah hasil dari ekspansi. (Memiliki RHS cocok dengan gumpalan LHS ketika direktori kosong tidak bekerja karena positif palsu yang terjadi ketika LHS glob cocok dengan satu file bernama glob itu sendiri: the
*
in the glob cocok dengan substring*
pada nama file. ) Ekspresi penjepit{,.[^.],..?}
mencakup file tersembunyi, tetapi tidak..
atau.
.Karena
shopt -s nullglob
dijalankan di dalam$()
(subkulit), itu tidak mengubahnullglob
opsi shell saat ini, yang biasanya merupakan hal yang baik. Di sisi lain, itu ide yang baik untuk mengatur opsi ini dalam skrip, karena itu adalah kesalahan untuk memiliki gumpalan mengembalikan sesuatu ketika tidak ada kecocokan. Jadi, seseorang dapat mengatur opsi nullglob di awal skrip dan itu tidak akan diperlukan dalam fungsinya. Ingatlah ini: kami menginginkan solusi yang berfungsi dengan opsi nullglob.Peringatan:
Jika kita tidak memiliki akses baca ke direktori, fungsinya melaporkan sama seperti jika ada direktori kosong. Ini berlaku juga untuk fungsi yang mencantumkan direktori dan menerima output.
The
shopt -s nullglob
perintah tidak standar POSIX.Ini menggunakan subkulit yang dibuat oleh
$()
. Ini bukan masalah besar, tapi menyenangkan jika kita bisa menghindarinya.Pro:
Bukan berarti itu penting, tetapi fungsi ini empat kali lebih cepat dari yang sebelumnya, diukur dengan jumlah waktu CPU yang dihabiskan di kernel dalam proses.
Solusi lain:
Kita dapat menghapus perintah non POSIX
shopt -s nullglob
pada LHS dan meletakkan string"$1/* $1/.[^.]* $1/..?*"
di RHS dan menghilangkan secara terpisah positif palsu yang terjadi ketika kita hanya memiliki file bernama'*'
,.[^.]*
atau..?*
di direktori:Tanpa
shopt -s nullglob
perintah, sekarang masuk akal untuk menghapus subkulit, tetapi kita harus berhati-hati karena kita ingin menghindari pemisahan kata dan belum mengizinkan ekspansi global pada LHS. Secara khusus mengutip untuk menghindari pemisahan kata tidak berfungsi, karena itu juga mencegah ekspansi gumpal. Solusi kami adalah mempertimbangkan gumpalan secara terpisah:Kami masih memiliki pemisahan kata untuk glob individu, tetapi tidak apa-apa sekarang, karena itu hanya akan menghasilkan kesalahan ketika direktori tidak kosong. Kami menambahkan 2> / dev / null, untuk membuang pesan kesalahan ketika ada banyak file yang cocok dengan bola yang diberikan pada LHS.
Kami ingat bahwa kami menginginkan solusi yang bekerja dengan opsi nullglob juga. Solusi di atas gagal dengan opsi nullglob, karena ketika direktori kosong, LHS juga kosong. Untungnya, tidak pernah dikatakan bahwa direktori tersebut kosong ketika tidak. Itu hanya gagal untuk mengatakan bahwa itu kosong ketika itu. Jadi, kita dapat mengelola opsi nullglob secara terpisah. Kami tidak dapat dengan mudah menambahkan kasus
[ "$1/"* = "" ]
dll. Karena ini akan berkembang sebagai[ = "" ]
, dll. Yang secara sintaksis salah. Jadi, kami menggunakan[ "$1/"* "" = "" ]
dll. Kita lagi harus mempertimbangkan tiga kasus*
,..?*
dan.[^.]*
untuk mencocokkan file yang tersembunyi, tetapi tidak.
dan..
. Ini tidak akan mengganggu jika kita tidak memiliki opsi nullglob, karena mereka juga tidak pernah mengatakan bahwa itu kosong ketika tidak ada. Jadi, solusi akhir yang diusulkan adalah:Masalah keamanan:
Buat dua file
rm
danx
dalam direktori kosong dan jalankan*
pada prompt. Glob*
akan meluas kerm x
dan ini akan dieksekusi untuk menghapusx
. Ini bukan masalah keamanan, karena dalam fungsi kami, gumpalan terletak di mana ekspansi tidak dilihat sebagai perintah, tetapi sebagai argumen, seperti difor f in *
.sumber
$(set -f; echo "$1"/*)
sepertinya cara penulisan yang agak rumit"$1/*"
. Dan ini tidak akan cocok dengan direktori atau file tersembunyi."$1/*"
(perhatikan tanda kutip termasuk*
), sehinggaset -f
dan subkulit tidak perlu untuk itu pada khususnya../* ./.[!.]* ./..?*
). Mungkin Anda bisa memasukkan itu untuk membuat fungsi lengkap.Inilah cara sederhana lain untuk melakukannya. Asumsikan D adalah nama path lengkap dari direktori yang ingin Anda uji kekosongan.
Kemudian
Ini berhasil karena
memiliki sebagai output
awk menghapus D dan jika ukurannya 0 direktori kosong.
sumber
sumber
echo
, yang Anda butuhkan hanyalahlist="$somedir/*"
. Juga, ini rumit dan rentan terhadap kesalahan. Anda belum menyebutkan bahwa OP harus memberikan jalur target dir termasuk garis miring, misalnya.