Bagaimana menggabungkan dua string untuk membangun jalur yang lengkap

96

Saya mencoba menulis skrip bash. Dalam skrip ini saya ingin pengguna memasukkan jalur direktori. Lalu saya ingin menambahkan beberapa string di akhir string ini dan membangun jalur ke beberapa subdirektori. Misalnya asumsikan pengguna memasukkan string seperti ini:

/home/user1/MyFolder

Sekarang saya ingin membuat 2 subdirektori di direktori ini dan menyalin beberapa file di sana.

/home/user1/MyFolder/subFold1
/home/user1/MyFolder/subFold2

Bagaimana saya bisa melakukan ini?

Hakim
sumber
1
Apa yang sudah kamu coba sejauh ini? Juga, apakah bagian dari pertanyaan Anda tentang mendapatkan masukan dari pengguna, dan bagian lainnya tentang membangun jalur? Atau hanya jalannya?
Levon

Jawaban:

137

Standar POSIX mengamanatkan bahwa beberapa /diperlakukan sebagai satu /dalam satu nama file. Jadi //dir///subdir////filesama dengan /dir/subdir/file.

Karena itu, menggabungkan dua string untuk membangun jalur yang lengkap semudah:

full_path="$part1/$part2"
Bukit pasir
sumber
11
Kecuali jika $ part1 bisa berupa string kosong.
Tuure Laurinolli
1
@TuureLaurinolli Saya tidak mengerti dari mana Anda berasal. Penggabungan di atas masih akan menghasilkan jalur yang valid. Jalur tersebut mungkin tidak ada, tetapi masih valid. misalnya. "" + "/" + "Documents"memberi "/Documents".
Bukit pasir
17
Jika bagian itu sendiri adalah jalur relatif, dan bagian1 mungkin kosong, maka hasilnya mungkin berubah dari jalur relatif ke jalur absolut.
Tuure Laurinolli
2
@TuureLaurinolli Kemudian Anda bisa menambahkan ./ke depan. Tapi mungkin pengguna ingin menggabungkan jalur absolut. Jika tidak, mereka bisa menambahkan ./ke depan untuk memaksa jalan menjadi relatif. Perhatikan juga bahwa "$path1/./$path2"sama dengan "$path1/$path2".
yyny
41
#!/bin/bash

read -p "Enter a directory: " BASEPATH

SUBFOLD1=${BASEPATH%%/}/subFold1
SUBFOLD2=${BASEPATH%%/}/subFold2

echo "I will create $SUBFOLD1 and $SUBFOLD2"

# mkdir -p $SUBFOLD1
# mkdir -p $SUBFOLD2

Dan jika Anda ingin menggunakan readline sehingga Anda mendapatkan penyelesaian dan semua itu, tambahkan a -eke panggilan ke read:

read -e -p "Enter a directory: " BASEPATH
Sean Bright
sumber
1
Sayangnya, ini tidak berfungsi saat BASEPATH kosong. Yang saya butuhkan adalah sesuatu seperti itu yang hanya menambahkan / jika belum berakhir garis miring DAN tidak kosong. Jadi, ketika itu berakhir pada karakter nama file yang sah.
Carlo Wood
17

Tidakkah hanya menggabungkan bagian dari jalan Anda mencapai apa yang Anda inginkan?

$ base="/home/user1/MyFolder/"
$ subdir="subFold1"
$ new_path=$base$subdir
$ echo $new_path
/home/user1/MyFolder/subFold1

Anda kemudian dapat membuat folder / direktori sesuai kebutuhan.

Salah satu konvensi adalah mengakhiri jalur direktori dengan /(misalnya /home/) karena jalur yang dimulai dengan / bisa disalahartikan dengan direktori root. Jika garis miring ganda ( //) digunakan di sebuah jalur, itu juga masih benar. Tapi, jika tidak ada garis miring yang digunakan pada salah satu variabel, itu akan menjadi salah (misalnya /home/user1/MyFoldersubFold1).

Levon
sumber
3
mengapa saya mendapatkan pesan ini: Myscript.sh: baris 4: / home / user1 / MyFolder / subFold1: Is a directory
Hakim
2
Anda kehilangan a / dari jalur. Tujuannya adalah /home/user1/MyFolder/subFold1 agar Anda perlu sebaris new_path=$base/$subdir. Tapi lalu apa yang Anda lakukan jika jalur yang diberikan menyertakan tanda '/'?
Thrasi
1
@ Thrasi tambahkan saja tanda '/' ke variabel subdir atau newpath=$base/$subdir/Anda dapat memainkannya langsung di baris perintah
pengguna12345
3
@ user12345, Ya ... masih membuat solusi di atas salah.
Thrasi
5

Skrip berikut mengkatenisasi beberapa jalur (relatif / absolut) (BASEPATH) dengan jalur relatif (SUBDIR):

shopt -s extglob
SUBDIR="subdir"
for BASEPATH in '' / base base/ base// /base /base/ /base//; do
  echo "BASEPATH = \"$BASEPATH\" --> ${BASEPATH%%+(/)}${BASEPATH:+/}$SUBDIR"
done

Outputnya adalah:

BASEPATH = "" --> subdir
BASEPATH = "/" --> /subdir
BASEPATH = "base" --> base/subdir
BASEPATH = "base/" --> base/subdir
BASEPATH = "base//" --> base/subdir
BASEPATH = "/base" --> /base/subdir
BASEPATH = "/base/" --> /base/subdir
BASEPATH = "/base//" --> /base/subdir

Ini shopt -s extglobhanya diperlukan untuk mengizinkan BASEPATH diakhiri pada beberapa garis miring (yang mungkin tidak masuk akal). Tanpa perluasan global, Anda dapat menggunakan:

echo ${BASEPATH%%/}${BASEPATH:+/}$SUBDIR

yang akan mengakibatkan kurang rapi tetapi tetap berfungsi:

BASEPATH = "" --> subdir
BASEPATH = "/" --> /subdir
BASEPATH = "base" --> base/subdir
BASEPATH = "base/" --> base/subdir
BASEPATH = "base//" --> base//subdir
BASEPATH = "/base" --> /base/subdir
BASEPATH = "/base/" --> /base/subdir
BASEPATH = "/base//" --> /base//subdir
Carlo Wood
sumber
1

Saya sedang mengerjakan skrip shell saya yang perlu melakukan beberapa jalur bergabung dengan hal-hal seperti yang Anda lakukan.

Masalahnya, kedua jalur seperti itu

/data/foo/bar

/data/foo/bar/ 

valid.

Jika saya ingin menambahkan file ke jalur ini seperti

/data/foo/bar/myfile

tidak ada metode asli (seperti os.path.join () di python) di shell untuk menangani situasi seperti itu.

Tapi aku menemukan tipuan

Misalnya, jalur dasar disimpan dalam variabel shell

BASE=~/mydir

dan nama file terakhir yang ingin Anda bergabung adalah

FILE=myfile

Kemudian Anda dapat menetapkan jalur baru Anda seperti ini

NEW_PATH=$(realpath ${BASE})/FILE

dan kemudian Anda akan mendapatkannya

$ echo $NEW_PATH

/path/to/your/home/mydir/myfile

alasannya cukup sederhana, perintah "realpath" akan selalu memangkas garis miring untuk Anda jika perlu

余晓晨
sumber
0
#!/usr/bin/env bash

mvFiles() {
    local -a files=( file1 file2 ... ) \
             subDirs=( subDir1 subDir2 ) \
             subDirs=( "${subDirs[@]/#/$baseDir/}" )

    mkdir -p "${subDirs[@]}" || return 1

    local x
    for x in "${subDirs[@]}"; do
        cp "${files[@]}" "$x"
    done
}



main() {
    local baseDir
    [[ -t 1 ]] && echo 'Enter a path:'
    read -re baseDir
    mvFiles "$baseDir"
}

main "$@"
ormaaj
sumber
0

Ini seharusnya berfungsi untuk dir kosong (Anda mungkin perlu memeriksa apakah string kedua dimulai dengan /yang harus diperlakukan sebagai jalur absolut?):

#!/bin/bash

join_path() {
    echo "${1:+$1/}$2" | sed 's#//#/#g'
}

join_path "" a.bin
join_path "/data" a.bin
join_path "/data/" a.bin

Keluaran:

a.bin
/data/a.bin
/data/a.bin

Referensi: Ekspansi Parameter Shell

tsl0922
sumber