Membangun jalur dengan kokoh

16

Katakanlah saya memiliki beberapa variabel dalam skrip shell (misalnya dalam zsh):

FOLDER_1, FOLDER_2, etc.

Variabel-variabel ini merujuk ke folder yang diturunkan /. Misalnya, jika saya memiliki jalan/home/me/stuff/items

variabelnya adalah:

FOLDER_1='home'
FOLDER_2='me'
FOLDER_3='stuff'

Sekarang, katakan bahwa saya ingin membangun kembali jalur yang sesuai dengan menggabungkan variabel. Salah satu cara yang mungkin adalah dengan membangun jalur sebagai berikut:

PATH=$FOLDER_1/$FOLDER_2/$FOLDER_3/

Namun, katakan bahwa beberapa variabel FOLDER_idatang dengan garis miring ke depan, sementara yang lain tidak (dan kita tidak tahu yang mana) misalnya

FOLDER_1='home'
FOLDER_2='stuff/'
FOLDER_3='items'

Pertanyaan saya adalah: Bagaimana saya bisa membangun jalan dengan kokoh? (mis. menghindari tebasan ganda, dan menambahkannya di tempat yang seharusnya).

Saya pikir salah satu cara untuk melakukan ini adalah dengan menambahkan /selalu di antara pasangan variabel, dan kemudian menghapus duplikat dengan sed, tetapi saya tidak bisa membuatnya bekerja (saya tidak yakin saya menangani /dengan benar di sed).

Juga, apakah saya menciptakan kembali kemudi ? (yaitu apakah sudah ada built-in yang melakukan ini?).

Pada akhirnya, jika variabel berada dalam array , misalnya FOLDERS, apakah mungkin untuk melakukan ini tanpa perulangan? (Atau sebagai alternatif, dengan looping tetapi tanpa mengetahui berapa banyak yang FOLDERSada dalam array).

Amelio Vazquez-Reina
sumber

Jawaban:

12

Anda bisa menggunakan printfdengan array:

parts=("$FOLDER_1" "$FOLDER_2" "$FOLDER_3");
printf '/%s' "${parts[@]%/}"
# Use "printf -v path" to save it into a variable called "path" instead of printing it

The %Operator trims tertinggal string, dalam hal ini /. Dengan menerapkannya parts[@], ia memotong setiap anggota array secara terpisah.

Kunci untuk memahami printftrik ini , adalah bagian ini dari man 1 printf: "Format string digunakan kembali sesering yang diperlukan untuk memuaskan argumen."

janmoesen
sumber
%Metode tunggal bekerja untuk slash trailing tunggal yang disebutkan dalam queston. Untuk melayani ketika ada beberapa garis miring, ${parts[@]%%/*}bekerja. Berikut ini tautan untuk info lebih lanjut tentang masalah slash: Apa arti slash ganda dalam jalur UNIX? Apakah 'cd dir / subdir // valid ...
Peter.O
2
@fered: /*dalam hal ini tidak berarti nol atau lebih garis miring , melainkan garis miring yang diikuti oleh sejumlah karakter. Itu berarti jika jalur Anda dimulai dengan garis miring, hasilnya akan menjadi string kosong!
l0b0
Saya telah mempertimbangkan, sebagai contoh, bahwa hanya akan ada garis miring. Namun, untuk beradaptasi dengan kemungkinan slash (es) terkemuka, bash'sextglob (with regex) dapat digunakan ... shopt -s extglob; ${parts[@]%%/+(/)}...
Peter.O
15

Jawaban sederhananya adalah untuk berhenti mengkhawatirkan dan menyukai banyak tebasan. Beberapa garis miring memiliki efek yang sama dengan garis miring tunggal (kecuali jalur yang dimulai dengan// arti berbeda pada beberapa sistem; lapisan emulasi unix pada Windows adalah satu-satunya yang dapat saya sebutkan). Itu dengan desain, dan mampu merakit nama file tanpa harus khawatir tentang beberapa garis miring adalah bagian utama dari keputusan desain itu.

Untuk bergabung dengan elemen array, di zsh, Anda dapat menggunakan j flag ekspansi parameter .

dir=${(j:/:)FOLDERS}

Anda dapat melumatkan garis miring duplikat saat Anda melakukannya, tapi itu murni kosmetik.

setopt extended_glob
dir=${${(j:/:)FOLDERS}//\/\/##/\/}

Di ksh dan bash, Anda bisa bergabung dengan array menggunakan karakter pertama $IFS sebagai pemisah. Anda kemudian dapat melumatkan garis miring duplikat. Dalam bash, Anda harus melakukan shopt -s extglobuntuk mengaktifkan gumpalan ksh di baris terakhir potongan di bawah ini.

IFS=/
dir="${FOLDERS[*]}"
unset IFS
dir=${dir//\/+(\/)//}
Gilles 'SANGAT berhenti menjadi jahat'
sumber
3

Bagaimana sedtidak bekerja untukmu? Coba sed 's|/\+|/|g'setelah penggabungan, atau sed 's|/||g'sebelumnya.

Kevin
sumber
1

bash 4memperkenalkan globbing luas, yang memungkinkan pencocokan ekspresi reguler dalam substitusi parameter ${var....}... Ini dimatikan secara default. Untuk mengaktifkannya untuk skrip Anda, cukup setel opsi shell extglob ...

Anggap $ dir ==/home/me/////////stuff//items

shopt -s extglob; dir="${dir//+(\/)//}"

Nilai yang dihasilkan dari $ dir

/home/me/stuff/items  

Berikut adalah beberapa contoh dengan do-dan-jangan-s - Bash Extended Globbing

Peter.O
sumber