Cách nối hai chuỗi để tạo đường dẫn hoàn chỉnh


93

Tôi đang cố gắng viết một kịch bản bash. Trong tập lệnh này, tôi muốn người dùng nhập đường dẫn của một thư mục. Sau đó, tôi muốn nối một số chuỗi vào cuối chuỗi này và xây dựng một đường dẫn đến một số thư mục con. Ví dụ: giả sử người dùng nhập một chuỗi như thế này:

/home/user1/MyFolder

Bây giờ tôi muốn tạo 2 thư mục con trong thư mục này và sao chép một số tệp vào đó.

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

Tôi có thể làm cái này như thế nào?


1
Bạn đã thử những gì cho đến nay? Ngoài ra, một phần câu hỏi của bạn là về việc lấy thông tin đầu vào từ người dùng và phần khác về việc xây dựng đường dẫn? Hay chỉ là con đường?
Levon

Câu trả lời:


135

Tiêu chuẩn POSIX quy định rằng nhiều tệp /được coi là /một tệp duy nhất trong tên tệp. Vì vậy //dir///subdir////file, giống như /dir/subdir/file.

Việc nối hai chuỗi như vậy để tạo một đường dẫn hoàn chỉnh đơn giản như sau:

full_path="$part1/$part2"

11
Ngoại trừ nếu $ part1 có thể là chuỗi trống.
Tuure Laurinolli

1
@TuureLaurinolli Tôi không hiểu bạn đến từ đâu. Việc nối ở trên sẽ vẫn dẫn đến một đường dẫn hợp lệ. Đường dẫn có thể không tồn tại, nhưng nó vẫn hợp lệ. ví dụ. "" + "/" + "Documents"cho "/Documents".
Dunes

17
Nếu bản thân các phần là đường dẫn tương đối và part1 có thể trống, thì kết quả có thể chuyển từ đường dẫn tương đối sang đường dẫn tuyệt đối.
Tuure Laurinolli

2
@TuureLaurinolli Sau đó, bạn có thể chỉ cần thêm ./vào phía trước. Nhưng có thể người dùng muốn nối các đường dẫn tuyệt đối. Nếu không, họ có thể chỉ cần thêm ./vào phía trước để buộc đường dẫn là tương đối. Cũng lưu ý rằng "$path1/./$path2"giống như "$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

Và nếu bạn muốn sử dụng dòng đọc để hoàn thành và tất cả những điều đó, hãy thêm a -evào lệnh gọi tới read:

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

1
Thật không may, điều này không hoạt động khi BASEPATH trống. Những gì tôi cần là một cái gì đó như vậy chỉ thêm a / khi nó chưa kết thúc dấu gạch chéo VÀ không trống. Do đó, khi nó kết thúc trên một ký tự tên tệp hợp pháp.
Carlo Wood

17

Sẽ không chỉ đơn giản là nối các phần của con đường của bạn để đạt được những gì bạn muốn?

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

Sau đó, bạn có thể tạo các thư mục / thư mục nếu cần.

Một quy ước là kết thúc các đường dẫn thư mục bằng /(ví dụ /home/) vì các đường dẫn bắt đầu bằng dấu / có thể bị nhầm lẫn với thư mục gốc. Nếu dấu gạch chéo kép ( //) được sử dụng trong một đường dẫn, nó cũng vẫn đúng. Tuy nhiên, nếu không có dấu gạch chéo nào được sử dụng trên một trong hai biến, nó sẽ không chính xác (ví dụ /home/user1/MyFoldersubFold1:).


3
tại sao tôi nhận được thông báo này: Myscript.sh: dòng 4: / home / user1 / MyFolder / subFold1: Là một thư mục
Hakim

2
Bạn đang thiếu a / từ đường dẫn. Mục tiêu là nội tuyến, /home/user1/MyFolder/subFold1 vì vậy bạn sẽ cần nội tuyến new_path=$base/$subdir. Nhưng sau đó bạn sẽ làm gì nếu đường dẫn được đưa ra có dấu '/'?
Thrasi

1
@Thrasi chỉ cần thêm dấu '/' hoặc vào biến subdir hoặc newpath=$base/$subdir/Bạn có thể chơi với điều này trực tiếp trên dòng lệnh
user12345

3
@ user12345, Có ... vẫn để lại giải pháp ở trên không chính xác.
Thrasi

5

Tập lệnh sau phân loại một số đường dẫn (tương đối / tuyệt đối) (BASEPATH) với một đường dẫn tương đối (SUBDIR):

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

Đầu ra của nó là:

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

Điều shopt -s extglobcần thiết duy nhất để cho phép BASEPATH kết thúc bằng nhiều dấu gạch chéo (điều này có lẽ là vô nghĩa). Nếu không có găng tay mở rộng, bạn chỉ có thể sử dụng:

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

điều này sẽ dẫn đến việc ít gọn gàng hơn nhưng vẫn hoạt động:

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

Tôi đang làm việc với tập lệnh shell của mình, nó cần thực hiện một số công cụ nối đường dẫn như bạn làm.

Vấn đề là, cả hai con đường như

/data/foo/bar

/data/foo/bar/ 

có giá trị.

Nếu tôi muốn nối một tệp vào đường dẫn này như

/data/foo/bar/myfile

không có phương thức gốc (như os.path.join () trong python) trong shell để xử lý tình huống như vậy.

Nhưng tôi đã tìm thấy một thủ thuật

Ví dụ: đường dẫn cơ sở được lưu trữ trong một biến shell

BASE=~/mydir

và tên tệp cuối cùng bạn muốn tham gia là

FILE=myfile

Sau đó, bạn có thể chỉ định đường dẫn mới của mình như thế này

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

và sau đó bạn sẽ nhận được

$ echo $NEW_PATH

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

lý do rất đơn giản, lệnh "realpath" sẽ luôn cắt bớt dấu gạch chéo kết thúc cho bạn nếu cần


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

Điều này sẽ hoạt động đối với dir trống (Bạn có thể cần phải kiểm tra xem chuỗi thứ hai bắt đầu bằng chuỗi /nào nên được coi là một đường dẫn tuyệt đối?):

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

Đầu ra:

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

Tham khảo: Mở rộng thông số Shell

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.