Как объединить две строки, чтобы построить полный путь

95

Я пытаюсь написать сценарий bash. В этом скрипте я хочу, чтобы пользователь ввел путь к каталогу. Затем я хочу добавить несколько строк в конец этой строки и построить путь к некоторым подкаталогам. Например, предположим, что пользователь вводит такую ​​строку:

/home/user1/MyFolder

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

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

Как я могу это сделать?

Хаким
источник
1
что ты уже испробовал? Кроме того, часть вашего вопроса связана с получением ввода от пользователя, а другая часть - с построением пути? Или просто путь?
Левон

Ответы:

136

Стандарт POSIX требует, чтобы несколько файлов /рассматривались как одно /в имени файла. Таким образом //dir///subdir////fileто же самое, что и /dir/subdir/file.

Таким образом, объединение двух строк для построения полного пути выполняется просто:

full_path="$part1/$part2"
Дюны
источник
11
За исключением случаев, когда $ part1 может быть пустой строкой.
Tuure Laurinolli 02
1
@TuureLaurinolli Я не понимаю, откуда вы. Вышеупомянутая конкатенация все равно приведет к действительному пути. Путь может не существовать, но он все равно действителен. например. "" + "/" + "Documents"дает "/Documents".
Dunes
17
Если сами части являются относительными путями, а часть part1 может быть пустой, тогда результат может измениться с относительного пути на абсолютный.
Tuure Laurinolli
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. Но что тогда делать, если указанный путь включает завершающий '/'?
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

Это должно работать для пустого каталога (вам может потребоваться проверить, начинается ли вторая строка, с /которой следует рассматривать как абсолютный путь?):

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

Ссылка: Расширение параметров оболочки

tsl0922
источник