Saya akhirnya menggunakan yang ini karena itu yang paling fleksibel dan ada beberapa hal serupa lainnya yang ingin saya lakukan juga bahwa ini bekerja dengan baik.
Lawrence Johnston
Ini mungkin yang paling fleksibel dari semua jawaban yang diposting, tapi saya pikir jawaban yang menyarankan perintah basename dan dirname layak mendapat perhatian juga. Mereka mungkin hanya trik jika Anda tidak memerlukan pencocokan pola mewah lainnya.
mgadda
7
Apa ini yang disebut $ {x% .bar}? Saya ingin belajar lebih banyak tentang itu.
Basil
14
@ Basil: Ekspansi Parameter. Pada konsol ketik "man bash" dan kemudian ketik "/ ekspansi parameter"
Zan Lynx
1
Saya kira penjelasan 'man bash' masuk akal jika Anda sudah tahu apa fungsinya atau jika Anda mencobanya sendiri dengan cara yang sulit. Ini hampir seburuk referensi git. Saya hanya akan google saja.
Mungkin yang paling sederhana dari semua solusi yang ditawarkan saat ini ... walaupun saya akan menggunakan $ (...) daripada backticks.
Michael Johnson
6
Sederhana tapi menambah ketergantungan (bukan yang besar atau aneh, saya akui). Itu juga perlu tahu sufiks.
Vinko Vrsalovic
Dan dapat digunakan untuk menghapus apa pun dari ujung, pada dasarnya itu hanya penghapusan string dari ujung.
Smar
2
Masalahnya adalah waktu yang tepat. Saya baru saja mencari pertanyaan untuk diskusi ini setelah menonton bash mengambil hampir 5 menit untuk memproses 800 file, menggunakan nama file. Menggunakan metode regex di atas, waktu dikurangi menjadi sekitar 7 detik. Meskipun jawaban ini lebih mudah dilakukan untuk programmer, waktu yang dihabiskan terlalu banyak. Bayangkan sebuah folder dengan beberapa ribu file di dalamnya! Saya punya beberapa folder seperti itu.
xizdaqrian
@ xizdaqrian Ini benar-benar salah. Ini adalah program sederhana, yang seharusnya tidak butuh setengah detik untuk kembali. Saya baru saja mengeksekusi find / home / me / dev -name "* .py" .py -exec basename {} \; dan itu menghapus ekstensi dan direktori untuk 1500 file dalam 1 detik total.
Laszlo Treszkai
40
Bash murni, dilakukan dalam dua operasi terpisah:
Hapus path dari path-string:
path=/foo/bar/bim/baz/file.gif
file=${path##*/} #$file is now 'file.gif'
Menggunakan nama bas saya menggunakan yang berikut untuk mencapai ini:
for file in*;do
ext=${file##*.}
fname=`basename $file $ext`# Do things with $fnamedone;
Ini tidak memerlukan pengetahuan apriori tentang ekstensi file dan berfungsi bahkan ketika Anda memiliki nama file yang memiliki titik-titik dalam nama file itu (di depan ekstensi itu); itu memang membutuhkan program basename, tetapi ini adalah bagian dari GNU coreutils sehingga harus dikirimkan dengan distro apa pun.
Fungsi ini dijelaskan pada man bash di bawah "Ekspansi Parameter". Cara non bash berlimpah: awk, perl, sed dan sebagainya.
EDIT: Bekerja dengan titik-titik di akhiran file dan tidak perlu tahu akhiran (ekstensi), tetapi tidak bekerja dengan titik-titik dalam nama itu sendiri.
Akan sangat membantu untuk memperbaiki kutipan di sini - mungkin jalankan ini melalui shellcheck.net dengan mystring=$1daripada nilai konstan saat ini (yang akan menekan beberapa peringatan, memastikan tidak mengandung spasi / karakter glob / dll), dan mengatasi masalah itu menemukan?
Charles Duffy
Yah, saya membuat beberapa perubahan yang sesuai untuk mendukung tanda kutip dalam $ mystring. Astaga, ini sudah lama sekali saya menulis ini :)
Jerub
Akan ada peningkatan lebih lanjut untuk mengutip hasil: echo "basename: $(basename "$mystring")"- dengan cara itu jika mystring='/foo/*'Anda tidak mendapatkan *diganti dengan daftar file di direktori saat ini setelahbasename selesai.
Charles Duffy
6
Menggunakan basenameasumsi bahwa Anda tahu apa ekstensi file itu, bukan?
Dan saya percaya bahwa berbagai saran ekspresi reguler tidak mengatasi nama file yang mengandung lebih dari satu "."
Berikut ini tampaknya mengatasi titik ganda. Oh, dan nama file yang berisi "/" sendiri (hanya untuk iseng)
Mengutip Pascal, "Maaf skrip ini terlalu panjang. Saya tidak punya waktu untuk membuatnya lebih pendek"
Ini bahkan dapat membuat nama file aman dengan memisahkan output dengan NUL byte menggunakan -zopsi, misalnya untuk file-file ini yang mengandung karakter kosong, baris baru dan gumpalan (dikutip oleh ls):
$ ls has*'has'$'\n''newline.bar''has space.bar''has*.bar'
Jika Anda tidak dapat menggunakan nama bas seperti yang disarankan dalam posting lain, Anda selalu dapat menggunakan sed. Berikut ini adalah contoh (jelek). Ini bukan yang terbaik, tetapi bekerja dengan mengekstraksi string yang diinginkan dan mengganti input dengan string yang diinginkan.
echo '/foo/fizzbuzz.bar'| sed 's|.*\/\([^\.]*\)\(\..*\)$|\1|g'
Meskipun ini adalah jawaban untuk pertanyaan awal, perintah ini berguna ketika saya memiliki garis path dalam file untuk mengekstrak nama dasar untuk mencetaknya ke layar.
Sangcheol Choi
2
Waspadalah terhadap solusi perl yang disarankan: ia menghilangkan apa pun setelah titik pertama.
$ echo some.file.with.dots | perl -pe 's/\..*$//;s{^.*/}{}'
some
Jika Anda ingin melakukannya dengan perl, ini berfungsi:
Nama dasarnya melakukan itu, menghilangkan path. Ini juga akan menghapus akhiran jika diberikan dan jika cocok dengan akhiran file tetapi Anda harus tahu akhiran untuk diberikan kepada perintah. Kalau tidak, Anda dapat menggunakan mv dan mencari tahu apa nama baru itu dengan cara lain.
${parameter%word}
dan${parameter%%word}
di bagian pencocokan porsi.Jawaban:
Inilah cara melakukannya dengan operator # dan% di Bash.
${x%.bar}
bisa juga${x%.*}
untuk menghapus semuanya setelah titik atau${x%%.*}
untuk menghapus semuanya setelah titik pertama.Contoh:
Dokumentasi dapat ditemukan di manual Bash . Cari
${parameter%word}
dan${parameter%%word}
ikuti bagian pencocokan porsi.sumber
lihat perintah basename:
sumber
Bash murni, dilakukan dalam dua operasi terpisah:
Hapus path dari path-string:
Hapus ekstensi dari path-string:
sumber
Menggunakan nama bas saya menggunakan yang berikut untuk mencapai ini:
Ini tidak memerlukan pengetahuan apriori tentang ekstensi file dan berfungsi bahkan ketika Anda memiliki nama file yang memiliki titik-titik dalam nama file itu (di depan ekstensi itu); itu memang membutuhkan program
basename
, tetapi ini adalah bagian dari GNU coreutils sehingga harus dikirimkan dengan distro apa pun.sumber
fname=`basename $file .$ext`
Cara bash murni:
Fungsi ini dijelaskan pada man bash di bawah "Ekspansi Parameter". Cara non bash berlimpah: awk, perl, sed dan sebagainya.
EDIT: Bekerja dengan titik-titik di akhiran file dan tidak perlu tahu akhiran (ekstensi), tetapi tidak bekerja dengan titik-titik dalam nama itu sendiri.
sumber
Fungsi nama dasar dan dirname adalah yang Anda cari:
Memiliki output:
sumber
mystring=$1
daripada nilai konstan saat ini (yang akan menekan beberapa peringatan, memastikan tidak mengandung spasi / karakter glob / dll), dan mengatasi masalah itu menemukan?echo "basename: $(basename "$mystring")"
- dengan cara itu jikamystring='/foo/*'
Anda tidak mendapatkan*
diganti dengan daftar file di direktori saat ini setelahbasename
selesai.Menggunakan
basename
asumsi bahwa Anda tahu apa ekstensi file itu, bukan?Dan saya percaya bahwa berbagai saran ekspresi reguler tidak mengatasi nama file yang mengandung lebih dari satu "."
Berikut ini tampaknya mengatasi titik ganda. Oh, dan nama file yang berisi "/" sendiri (hanya untuk iseng)
Mengutip Pascal, "Maaf skrip ini terlalu panjang. Saya tidak punya waktu untuk membuatnya lebih pendek"
sumber
Selain sintaks konforman POSIX yang digunakan dalam jawaban ini ,
seperti dalam
GNU
basename
mendukung sintaks lain:dengan hasil yang sama. Perbedaan dan keuntungannya adalah yang
-s
menyiratkan-a
, yang mendukung banyak argumen:Ini bahkan dapat membuat nama file aman dengan memisahkan output dengan NUL byte menggunakan
-z
opsi, misalnya untuk file-file ini yang mengandung karakter kosong, baris baru dan gumpalan (dikutip olehls
):Membaca ke dalam array:
readarray -d
membutuhkan Bash 4.4 atau yang lebih baru. Untuk versi yang lebih lama, kita harus mengulang:sumber
sumber
Jika Anda tidak dapat menggunakan nama bas seperti yang disarankan dalam posting lain, Anda selalu dapat menggunakan sed. Berikut ini adalah contoh (jelek). Ini bukan yang terbaik, tetapi bekerja dengan mengekstraksi string yang diinginkan dan mengganti input dengan string yang diinginkan.
Yang akan memberi Anda output
sumber
Waspadalah terhadap solusi perl yang disarankan: ia menghilangkan apa pun setelah titik pertama.
Jika Anda ingin melakukannya dengan perl, ini berfungsi:
Tetapi jika Anda menggunakan Bash, solusi dengan
y=${x%.*}
(ataubasename "$x" .ext
jika Anda tahu ekstensi) jauh lebih sederhana.sumber
Nama dasarnya melakukan itu, menghilangkan path. Ini juga akan menghapus akhiran jika diberikan dan jika cocok dengan akhiran file tetapi Anda harus tahu akhiran untuk diberikan kepada perintah. Kalau tidak, Anda dapat menggunakan mv dan mencari tahu apa nama baru itu dengan cara lain.
sumber
Menggabungkan jawaban berperingkat teratas dengan jawaban peringkat kedua untuk mendapatkan nama file tanpa path lengkap:
sumber