Отримати шлях до каталогу файлів із шляху файлу


400

У Bash, якщо VAR="/home/me/mydir/file.c", як я можу отримати "/home/me/mydir"?

Відповіді:


647

dirnameі basenameце інструменти, які ви шукаєте для вилучення компонентів контуру:

$ VAR=/home/me/mydir/file.c

$ DIR=$(dirname "${VAR}")

$ echo "${DIR}"
/home/me/mydir

$ basename "${VAR}"
file.c

Вони не є внутрішніми командами Bash, але вони є частиною стандарту POSIX (див. dirname, basename), І тому вони повинні бути доступні для переважної більшості систем, на яких буде працювати Bash.


4
Навіщо використовувати дужки навколо імен змінних, а не "$ VAR", наприклад?
користувач658182

1
stackoverflow.com/questions/8748831/… відповідає на вищезазначене питання.
користувач658182

1
@ user658182 У цьому конкретному прикладі це робиться за звичкою, а не за необхідністю.
Покинутий кошик

95
$ export VAR=/home/me/mydir/file.c
$ export DIR=${VAR%/*}
$ echo "${DIR}"
/home/me/mydir

$ echo "${VAR##*/}"
file.c

Щоб уникнути залежності з basenameіdirname


3
Оскільки обидва є частиною POSIX, залежність не повинна бути проблемою.
orkoden

1
orkoden, ти маєш рацію. Мета моєї відповіді - показати, що немає жодного зобов'язання виконувати два додаткові процеси. bash є самодостатнім для випадку використання.
Еммануель Дево

2
Я використовую метод Еммануеля, тому що я хочу передати або файл, або ім'я папки, а потім обчислити шлях до папки. Використання цього регулярного вираження робить все правильно, тоді як функція dirname повертає батьківську папку під час введення папки.
AnneTheAgile

8
Однак якщо інформація про шлях у $ VAR відсутня, $ {VAR% / *} / test створює несподіване значення, рівне $ VAR / тесту, тоді як $ (dirname $ VAR) дасть більш передбачуване та відповідне значення ./test. Це велика справа, оскільки перший намагатиметься розглядати ім'я файлу як каталог, а другий буде добре.
Деймірон

19

Якщо пов'язана примітка, якщо у вас є лише ім'я файлу або відносний шлях, dirnameсамостійно це не допоможе. Для мене відповідь зрештою була readlink.

fname='txtfile'    
echo $(dirname "$fname")                # output: .
echo $(readlink -f "$fname")            # output: /home/me/work/txtfile

Потім ви можете об'єднати два, щоб отримати лише каталог.

echo $(dirname $(readlink -f "$fname")) # output: /home/me/work

1
якщо більше одного компонента шляху не існувало, вам слід використовувати readlink -m "$fname"
кананізацію

7

Якщо ви хочете, щоб цільові файли були символічним посиланням, по-перше, ви можете перевірити його та отримати оригінальний файл. Пункт "if" нижче може вам допомогти.

if [ -h $file ]
then
 base=$(dirname $(readlink $file))
else
 base=$(dirname $file)
fi

5

Я грав із цим і придумав альтернативу.

$ VAR=/home/me/mydir/file.c

$ DIR=`echo $VAR |xargs dirname`

$ echo $DIR
/home/me/mydir

Частина, яка мені сподобалася, це було легко розширити резервну копію дерева:

$ DIR=`echo $VAR |xargs dirname |xargs dirname |xargs dirname`

$ echo $DIR
/home

1

Ось сценарій, який я використовував для рекурсивної обрізки. Звичайно, замініть $ 1 на потрібний вам каталог.

BASEDIR="$1"
IFS=$'\n'
cd $BASEDIR
 for f in $(find . -type f -name ' *')
 do 
    DIR=$(dirname "$f")
    DIR=${DIR:1}
    cd $BASEDIR$DIR
    rename 's/^ *//' *
 done

0

По-перше, я замінив /порожній простір ( ). Потім я видалив усі символи перед порожнім пробілом ( ). Наприкінці я видалив перший символ, який порожній пробіл ( ).

$ VAR="/home/me/mydir/file.c"

$ echo $VAR | tr '/' ' ' | sed 's/^.* / /' | cut -c2-
file.c

0
HERE=$(cd $(dirname $BASH_SOURCE) && pwd)

де ви отримуєте повний шлях з new_path = $(dirname ${BASH_SOURCE[0]}). Ви змінюєте поточний каталог за допомогою cd new_path та запустіть, pwdщоб отримати повний шлях до поточного каталогу.

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