วิธีเชื่อมสองสตริงเข้าด้วยกันเพื่อสร้างเส้นทางที่สมบูรณ์


95

ฉันกำลังพยายามเขียนสคริปต์ทุบตี ในสคริปต์นี้ฉันต้องการให้ผู้ใช้ป้อนเส้นทางของไดเร็กทอรี จากนั้นฉันต้องการต่อท้ายสตริงบางส่วนที่ส่วนท้ายของสตริงนี้และสร้างเส้นทางไปยังไดเร็กทอรีย่อย ตัวอย่างเช่นสมมติว่าผู้ใช้ป้อนสตริงดังนี้:

/home/user1/MyFolder

ตอนนี้ฉันต้องการสร้างไดเร็กทอรีย่อย 2 ไดเร็กทอรีนี้และคัดลอกไฟล์บางไฟล์ที่นั่น

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

ฉันจะทำเช่นนี้ได้อย่างไร?


1
คุณได้ลองทำอะไรมาบ้าง? นอกจากนี้ยังเป็นส่วนหนึ่งของคำถามของคุณเกี่ยวกับการรับข้อมูลจากผู้ใช้และส่วนอื่น ๆ เกี่ยวกับการสร้างเส้นทางหรือไม่ หรือแค่เส้นทาง?
Levon

คำตอบ:


136

มาตรฐาน POSIX กำหนดให้หลาย ๆ/ถือว่าเป็นหนึ่งเดียว/ในชื่อไฟล์ ดังนั้นจึง เป็นเช่นเดียวกับ//dir///subdir////file/dir/subdir/file

ดังนั้นการเชื่อมสตริงสองสตริงเข้าด้วยกันเพื่อสร้างพา ธ ที่สมบูรณ์จึงทำได้ง่าย ๆ ดังนี้:

full_path="$part1/$part2"

11
ยกเว้นว่า $ part1 สามารถเป็นสตริงว่างได้
Tuure Laurinolli

1
@TuureLaurinolli ฉันไม่เข้าใจว่าคุณมาจากไหน การต่อข้อมูลข้างต้นจะยังคงส่งผลให้มีเส้นทางที่ถูกต้อง เส้นทางอาจไม่มีอยู่จริง แต่ก็ยังใช้ได้ เช่น. "" + "/" + "Documents"ให้"/Documents".
Dunes

17
หากส่วนต่างๆเป็นพา ธ สัมพัทธ์และ part1 อาจว่างเปล่าผลลัพธ์อาจเปลี่ยนจากสัมพัทธ์เป็นพา ธ สัมบูรณ์
Tuure Laurinolli

2
@TuureLaurinolli จากนั้นคุณสามารถเพิ่ม./ที่ด้านหน้า แต่บางทีผู้ใช้อาจต้องการเชื่อมต่อพา ธ สัมบูรณ์ มิฉะนั้นพวกเขาสามารถเพิ่ม./ที่ด้านหน้าเพื่อบังคับเส้นทางให้สัมพันธ์กัน นอกจากนี้ทราบว่าเป็นเช่นเดียวกับ"$path1/./$path2" "$path1/$path2"

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

และถ้าคุณต้องการใช้ readline เพื่อให้คุณทำสำเร็จและทั้งหมดนั้นให้เพิ่ม-eการโทรไปที่read:

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

1
ขออภัยไม่สามารถใช้งานได้เมื่อ BASEPATH ว่างเปล่า สิ่งที่ฉันต้องการคือสิ่งที่เพิ่ม / เมื่อมันยังไม่สิ้นสุดของเครื่องหมายทับและไม่ว่างเปล่า ดังนั้นเมื่อมันจบลงด้วยอักขระชื่อไฟล์ทางกฎหมาย
Carlo Wood

17

จะไม่เพียงเชื่อมต่อส่วนหนึ่งของเส้นทางของคุณเพื่อให้บรรลุสิ่งที่คุณต้องการ?

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

จากนั้นคุณสามารถสร้างโฟลเดอร์ / ไดเรกทอรีได้ตามต้องการ

หลักการอย่างหนึ่งคือการสิ้นสุดพา ธ ไดเร็กทอรีด้วย/(เช่น/home/) เนื่องจากพา ธ ที่ขึ้นต้นด้วย / อาจสับสนกับไดเร็กทอรีราก หากใช้เครื่องหมายทับคู่ ( //) ในพา ธ ก็ยังถูกต้องเช่นกัน แต่ถ้าไม่มีการใช้เครื่องหมายทับในตัวแปรใดตัวแปรหนึ่งก็จะไม่ถูกต้อง (เช่น/home/user1/MyFoldersubFold1)


3
ทำไมฉันถึงได้รับข้อความนี้: Myscript.sh: บรรทัด 4: / home / user1 / MyFolder / subFold1: เป็นไดเร็กทอรี
Hakim

2
คุณไม่มี / จากเส้นทาง เป้าหมายของเราคืออินไลน์เพื่อให้คุณจะต้องอินไลน์/home/user1/MyFolder/subFold1 new_path=$base/$subdirแต่คุณจะทำอย่างไรถ้าเส้นทางที่ระบุมีเครื่องหมาย "/" ต่อท้าย?
Thrasi

1
@Thrasi เพียงเพิ่ม '/' ต่อท้ายตัวแปร subdir หรือnewpath=$base/$subdir/คุณสามารถเล่นกับสิ่งนี้โดยตรงบนบรรทัดคำสั่ง
user12345

3
@ user12345 ใช่ ... ยังปล่อยวิธีแก้ปัญหาด้านบนไม่ถูกต้อง
Thrasi

5

สคริปต์ต่อไปนี้รองรับหลายพา ธ (สัมพัทธ์ / สัมบูรณ์) (BASEPATH) ด้วยพา ธ สัมพัทธ์ (SUBDIR):

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

ผลลัพธ์คือ:

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 extglobเป็นสิ่งที่จำเป็นเท่านั้นที่จะช่วยให้ basepath ที่จะสิ้นสุดในวันที่ทับหลาย (ซึ่งอาจจะเป็นเรื่องไร้สาระ) คุณสามารถใช้:

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

ซึ่งจะส่งผลให้ความเรียบร้อยน้อยลง แต่ยังใช้งานได้:

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

ฉันกำลังทำงานกับเชลล์สคริปต์ของฉันซึ่งจำเป็นต้องเชื่อมโยงเส้นทางบางอย่างเช่นเดียวกับที่คุณทำ

สิ่งนี้คือทั้งสองเส้นทางเช่น

/data/foo/bar

/data/foo/bar/ 

ถูกต้อง

หากฉันต้องการต่อท้ายไฟล์กับเส้นทางนี้เช่น

/data/foo/bar/myfile

ไม่มีเมธอดดั้งเดิม (เช่น os.path.join () ใน python) ในเชลล์เพื่อจัดการกับสถานการณ์ดังกล่าว

แต่ฉันพบเคล็ดลับ

ตัวอย่างเช่นพา ธ พื้นฐานถูกเก็บไว้ในตัวแปรเชลล์

BASE=~/mydir

และนามสกุลไฟล์ที่คุณต้องการเข้าร่วมคือ

FILE=myfile

จากนั้นคุณสามารถกำหนดเส้นทางใหม่ของคุณเช่นนี้

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

แล้วคุณจะได้รับ

$ echo $NEW_PATH

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

เหตุผลนั้นง่ายมากคำสั่ง "realpath" มักจะตัดเฉือนการยุติให้คุณหากจำเป็น


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

สิ่งนี้ควรใช้กับ dir ว่างเปล่า (คุณอาจต้องตรวจสอบว่าสตริงที่สองเริ่มต้นด้วย/สิ่งที่ควรถือว่าเป็นพา ธ สัมบูรณ์หรือไม่):

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

เอาท์พุต:

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

ข้อมูลอ้างอิง: การขยายพารามิเตอร์เชลล์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.