Tam bir yol oluşturmak için iki dize nasıl birleştirilir


96

Bir bash senaryosu yazmaya çalışıyorum. Bu komut dosyasında kullanıcının bir dizinin yolunu girmesini istiyorum. Sonra bu dizenin sonuna bazı dizeler eklemek ve bazı alt dizinlere bir yol oluşturmak istiyorum. Örneğin, kullanıcının aşağıdaki gibi bir dizge girdiğini varsayın:

/home/user1/MyFolder

Şimdi bu dizinde 2 alt dizin oluşturmak ve oraya bazı dosyaları kopyalamak istiyorum.

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

Bunu nasıl yapabilirim?


1
Şimdiye kadar ne denedin? Ayrıca, sorunuzun bir kısmı kullanıcıdan girdi almakla ilgili, diğer kısmı da yolu oluşturmakla ilgili mi? Yoksa sadece yol mu?
Levon

Yanıtlar:


140

POSIX standardı, çokluların bir dosya adında /tek olarak ele alınmasını zorunlu kılar /. Böylece //dir///subdir////fileaynıdır /dir/subdir/file.

Tam bir yol oluşturmak için iki dizeyi birleştirmek şu kadar basittir:

full_path="$part1/$part2"

14
$ Part1'in boş dizge olabilmesi dışında.
Tuure Laurinolli

1
@TuureLaurinolli Nereden geldiğini anlamıyorum. Yukarıdaki birleştirme, yine de geçerli bir yolla sonuçlanacaktır. Yol mevcut olmayabilir, ancak yine de geçerli olacaktır. Örneğin. "" + "/" + "Documents"verir "/Documents".
Dunes

19
Parçaların kendileri göreceli yollarsa ve bölüm1 boşsa, sonuç göreceli yoldan mutlak yola dönüşebilir.
Tuure Laurinolli

2
@TuureLaurinolli O zaman basitçe öne ekleyebilirsiniz ./. Ama belki kullanıcı istediği mutlak yolları Concat için. Aksi takdirde ./, yolu göreceli olmaya zorlamak için basitçe öne ekleyebilirlerdi . Ayrıca bunun "$path1/./$path2"ile aynı olduğunu unutmayın "$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

Ve tamamlama ve tüm bunları elde etmek için readline kullanmak istiyorsanız -e, çağrıya bir ekleyin read:

read -e -p "Enter a directory: " BASEPATH

1
Maalesef bu BASEPATH boşken çalışmıyor. İhtiyacım olan şey, sadece bir bölü çizgisiyle bitmediğinde VE boş olmadığında / ekleyen böyle bir şey. Böylece, yasal bir dosya adı karakteri ile bittiğinde.
Carlo Wood

18

Yolunuzun bir kısmını sıraya dizmek istediğinizi başaramaz mı?

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

Daha sonra gerektiğinde klasörleri / dizinleri oluşturabilirsiniz.

Bir kural, dizin yollarını /(örneğin /home/) ile sonlandırmaktır, çünkü a / ile başlayan yollar kök dizin ile karıştırılabilir. //Bir yolda çift ​​eğik çizgi ( ) kullanılmışsa, yine de doğrudur. Ancak, her iki değişkende de eğik çizgi kullanılmazsa, yanlış olur (örneğin /home/user1/MyFoldersubFold1).


3
neden bu mesajı alıyorum: Myscript.sh: line 4: / home / user1 / MyFolder / subFold1: is a directory
Hakim

2
Yolda bir / eksiksiniz. Hedef satır içi olduğundan satır içi /home/user1/MyFolder/subFold1 gerekir new_path=$base/$subdir. Peki, verilen yol sonunda "/" içeriyorsa ne yaparsınız?
Thrasi

1
@Thrasi sadece sondaki '/' alt dizin değişkenine ekleyin veya newpath=$base/$subdir/bununla doğrudan komut satırında oynayabilirsiniz
user12345

3
@ user12345, Evet ... yine de yukarıdaki çözümü yanlış bırakıyor.
Thrasi

5

Aşağıdaki komut dosyası, göreli bir yolla (SUBDIR) birkaç (göreceli / mutlak) yolu (BASEPATH) katenat eder:

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

Bunun çıktısı:

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

shopt -s extglobBasePath (saçma muhtemelen olan) birden eğik çizgiler bitmesini sağlamak için gereklidir. Uzatılmış globing olmadan sadece şunları kullanabilirsiniz:

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

bu, daha az temiz ama yine de işe yarayacak

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

1

Senin yaptığın gibi bazı yollara katılma yoluna gitmesi gereken kabuk betiğim üzerinde çalışıyordum.

Mesele şu ki, her iki yol da

/data/foo/bar

/data/foo/bar/ 

geçerli.

Bu yola şöyle bir dosya eklemek istersem

/data/foo/bar/myfile

Shell'de böyle bir durumu ele almak için yerel bir yöntem (python'daki os.path.join () gibi) yoktu.

Ama bir numara buldum

Örneğin, temel yol bir kabuk değişkeninde depolandı

BASE=~/mydir

ve katılmak istediğin son dosya adı

FILE=myfile

Sonra yeni yolunu şöyle atayabilirsin

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

ve sonra alacaksın

$ echo $NEW_PATH

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

nedeni oldukça basit, "realpath" komutu gerekirse sizin için her zaman sonlandırıcı eğik çizgiyi keser


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 "$@"

0

Bu, boş dizin için çalışmalıdır (İkinci dizenin /mutlak yol olarak görülmesi gereken ikinci dizenin başlayıp başlamadığını kontrol etmeniz gerekebilir ?):

#!/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

Çıktı:

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

Referans: Kabuk Parametre Genişletme

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.