Як об’єднати два рядки для побудови повного шляху


93

Я намагаюся написати скрипт bash. У цьому сценарії я хочу, щоб користувач ввів шлях до каталогу. Потім я хочу додати рядки в кінці цього рядка і побудувати шлях до деяких підкаталогів. Наприклад, припустимо, що користувач вводить такий рядок:

/home/user1/MyFolder

Тепер я хочу створити 2 підкаталоги в цьому каталозі та скопіювати там деякі файли.

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

Як я можу це зробити?


1
Що ви пробували дотепер? Крім того, це частина вашого запитання про отримання вхідних даних від користувача, а інша частина про побудову шляху? Або просто стежка?
Левон,

Відповіді:


135

Стандартні мандати POSIX вимагають, щоб множинні в імені файлу /розглядалися як єдині /. Таким чином, //dir///subdir////fileце те саме, що /dir/subdir/file.

Таким чином, об'єднання двох рядків для побудови повного шляху є таким простим, як:

full_path="$part1/$part2"

11
За винятком, якщо $ part1 може бути порожнім рядком.
Тууре Лауріноллі

1
@TuureLaurinolli Я не розумію, звідки ти родом. Наведене вище об’єднання все одно призведе до дійсного шляху. Шлях може не існувати, але він все ще буде дійсним. напр. "" + "/" + "Documents"дає "/Documents".
Дюни

17
Якщо самі частини є відносними шляхами, а частина1 може бути порожньою, тоді результат може перетворитися із відносного на абсолютний шлях.
Тууре Лауріноллі

2
@TuureLaurinolli Тоді ви можете просто додати ./в передній частині. Але, можливо, користувач хоче поєднати абсолютні шляхи. Інакше вони могли просто додати ./до фронту, щоб змусити шлях бути відносним. Також зверніть увагу, що "$path1/./$path2"це те саме, що "$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

І якщо ви хочете використовувати лінію читання, щоб отримати завершення і все таке, додайте -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: Це каталог
Хакім

2
Вам не вистачає / зі шляху. Мета вбудована, /home/user1/MyFolder/subFold1 тому вам знадобиться вбудована new_path=$base/$subdir. Але що тоді робити, якщо вказаний шлях включає кінцевий '/'?
Фразі

1
@Thrasi просто додайте завершальний '/' або до змінної subdir, або newpath=$base/$subdir/Ви можете грати з цим безпосередньо в командному рядку
user12345

3
@ user12345, так ... рішення все ще залишає неправильним.
Фразі

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

Це має працювати для порожнього каталогу (можливо, вам доведеться перевірити, чи починається другий рядок, /який слід розглядати як абсолютний шлях?):

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

Довідково: Розширення параметра оболонки

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.