Получить текущее имя каталога (без полного пути) в скрипте Bash

547

Как получить только текущее имя рабочего каталога в bash script, или даже лучше, просто команду терминала.

pwd дает полный путь к текущему рабочему каталогу, например. /opt/local/bin, но я хочу только bin

Теги:
terminal

19 ответов

728
Лучший ответ

Нет необходимости в basename, и, особенно, нет необходимости в pwd подголовника (который добавляет дополнительную и дорогую вилку операция); оболочка может сделать это внутренне, используя расширение параметра:

result=${PWD##*/}          # to assign to a variable

printf '%s\n' "${PWD##*/}" # to print to stdout
                           # ...more robust than echo for unusual names
                           #    (consider a directory named -e or -n)

printf '%q\n' "${PWD##*/}" # to print to stdout, quoted for use as shell input
                           # ...useful to make hidden characters readable.
  • 25
    В чем разница между $ {PWD ## * /} и $ PWD?
  • 19
    @Mr_Chimp первый - это операция расширения параметра, которая обрезает остальную часть каталога, чтобы предоставить только базовое имя. В моем ответе есть ссылка на документацию по расширению параметров; не стесняйтесь следовать этому, если у вас есть какие-либо вопросы.
Показать ещё 26 комментариев
166

Используйте программу basename. Для вашего случая:

% basename "$PWD"
bin
  • 16
    Разве это не цель программы basename ? Что не так с этим ответом, кроме пропущенных кавычек?
  • 7
    @Nacht basename - это действительно внешняя программа, которая делает правильные вещи, но запускать любую внешнюю программу для чего-то, что bash может делать из коробки, используя только встроенную функциональность, глупо, что сказывается на производительности ( fork() , execve() , wait() и т. д.) без причины.
Показать ещё 11 комментариев
105
$ echo "${PWD##*/}"

  • 8
    Этот парень был более ясен в отношении echo , Чарли;)
  • 2
    @jocap ... за исключением того, что использование echo там без указания аргумента неверно . Если имя каталога имеет несколько пробелов или символ табуляции, оно будет свернуто в один пробел; если он имеет подстановочный знак, он будет расширен. Правильное использование будет echo "${PWD##*/}" .
Показать ещё 1 комментарий
19

Вы можете использовать комбинацию pwd и basename. Например.

#!/bin/bash

CURRENT=`pwd`
BASENAME=`basename "$CURRENT"`

echo "$BASENAME"

exit;
  • 15
    Пожалуйста, нет. Обратные метки создают подоболочку (таким образом, операцию разветвления) - и в этом случае вы используете их дважды ! [В качестве дополнительного, хотя и стилистического, смысла - имена переменных должны быть в нижнем регистре, если вы не экспортируете их в среду или они представляют собой особый, зарезервированный регистр].
  • 11
    и в качестве второго стиля придирки следует заменить на $ (). все еще вилки, но более удобочитаемые и с меньшими затратами.
Показать ещё 2 комментария
9

Как насчет grep:

pwd | grep -o '[^/]*$'
  • 0
    не рекомендую, потому что кажется, что он получает некоторую информацию о цвете, тогда как pwd | xargs basename не ... вероятно, не так важно, но другой ответ проще и более согласован в разных средах
6

Мне нравится выбранный ответ (Charles Duffy), но будьте осторожны, если вы находитесь в символическом каталоге, и вам нужно имя целевого каталога. К сожалению, я не думаю, что это можно сделать в одном выражении расширения параметра, возможно, я ошибаюсь. Это должно работать:

target_PWD=$(readlink -f .)
echo ${target_PWD##*/}

Чтобы увидеть это, эксперимент:

cd foo
ln -s . bar
echo ${PWD##*/}

сообщает "bar"

DIRNAME

Чтобы показать ведущие каталоги пути (без возникновения fork-exec из /usr/bin/dirname ):

echo ${target_PWD%/*}

Это будет, например, transform foo/bar/baz → foo/bar

  • 4
    К сожалению, readlink -f является расширением GNU и поэтому недоступна на BSD (включая OS X).
  • 0
    Но есть несколько альтернатив.
5
echo "$PWD" | sed 's!.*/!!'

Если вы используете оболочку Bourne или ${PWD##*/} недоступно.

  • 4
    К вашему сведению, ${PWD##*/} - это POSIX sh - каждый современный / bin / sh (включая тире, пепел и т. Д.) Поддерживает это; чтобы поразить настоящую Борн на недавнем боксе, вам нужно будет использовать слегка устаревшую систему Solaris. Помимо этого - echo "$PWD" ; пропуск кавычек приводит к ошибкам (если в имени каталога есть пробелы, символы подстановки и т. д.).
  • 1
    Да, я использовал старую систему Solaris. Я обновил команду для использования кавычек.
4

Эта тема замечательная! Вот еще один вкус:

pwd | awk -F / '{print $NF}'
2

Удивительно, но никто не упомянул об этой альтернативе, которая использует только встроенные команды bash:

i="$IFS";IFS='/';set -f;p=($PWD);set +f;IFS="$i";echo "${p[-1]}"

В качестве добавленного бонуса вы можете легко получить имя родительского каталога:

[ "${#p[@]}" -gt 1 ] && echo "${p[-2]}"

Они будут работать на bash 4.3-alpha или новее.

  • 0
    удивительно ? просто шучу, но другие намного короче и их легче запомнить
  • 0
    Это довольно забавно = P до этого не слышал о $ IFS (внутренний разделитель полей). мой bash был слишком стар, но можете проверить его здесь: jdoodle.com/test-bash-shell-script-online
1

очень просто

pwd | xargs basename
1

Ниже grep с регулярным выражением также работает,

>pwd | grep -o "\w*-*$"
  • 2
    Не работает, если имя каталога содержит символы "-".
1

Я обычно использую это в сценариях sh

SCRIPTSRC=`readlink -f "$0" || echo "$0"`
RUN_PATH=`dirname "${SCRIPTSRC}" || echo .`
echo "Running from ${RUN_PATH}"
...
cd ${RUN_PATH}/subfolder

вы можете использовать это для автоматизации...

  • 0
    readlink: illegal option -- f usage: readlink [-n] [file ...]
1
basename $(pwd)

или

echo "$(basename $(pwd))"
  • 1
    Требуется больше кавычек, чтобы быть правильными - как таковой, вывод pwd разбивается на строки и расширяется до basename перед передачей в basename .
0

Я предпочитаю использовать gbasename, который является частью GNU coreutils.

  • 0
    К вашему сведению, это не входит в мой дистрибутив Ubuntu.
0

Чтобы найти там жокеев вроде меня:

find $PWD -maxdepth 0 -printf "%f\n"
0

Следующие команды приведут к печати текущего рабочего каталога в bash script.

pushd .
CURRENT_DIR="`cd $1; pwd`"
popd
echo $CURRENT_DIR
  • 2
    (1) Я не уверен, где мы гарантируем, что список аргументов таков, что $1 будет содержать текущий рабочий каталог. (2) pushd и popd не служат никакой цели здесь , потому что что - то внутри обратных кавычек делается в субоболочке - поэтому он не может повлиять на каталог родительской оболочки, чтобы начать с. (3) Использование "$(cd "$1"; pwd)" будет более читабельным и устойчивым к именам каталогов с пробелами.
-2

Я использую эту команду:

dirname "$0"

  • 0
    Возвращает /bin ?????
  • 0
    О, это возвращает полный путь ...
-2

Просто используйте:

pwd | xargs basename

или

basename "`pwd`"
  • 2
    Это во всех отношениях худшая версия ответа, ранее предоставленного Аркадием ( stackoverflow.com/a/1371267/14122 ): xargs xargs неэффективна и содержит ошибки, когда имена каталогов содержат буквальные символы новой строки или символы кавычек, а вторая формулировка вызывает Команда pwd в подоболочке, вместо того, чтобы получить тот же результат через расширение встроенной переменной.
-2

Вы можете использовать служебную программу basename, которая удаляет любой префикс, заканчивающийся в/и суффикс (если присутствует в строке) из строки, и печатает результат на стандартном выходе.

$basename <path-of-directory>

Ещё вопросы

Сообщество Overcoder
Наверх
Меню