Jak uzyskać aktualną nazwę katalogu roboczego w skrypcie bash, a jeszcze lepiej, po prostu polecenie terminalu.
pwd
podaje pełną ścieżkę bieżącego katalogu roboczego, np. /opt/local/bin
ale chcę tylkobin
Jak uzyskać aktualną nazwę katalogu roboczego w skrypcie bash, a jeszcze lepiej, po prostu polecenie terminalu.
pwd
podaje pełną ścieżkę bieżącego katalogu roboczego, np. /opt/local/bin
ale chcę tylkobin
Odpowiedzi:
Nie ma potrzeby używania nazwy basename, a zwłaszcza podpowłoki z pwd (co dodaje dodatkową i kosztowną operację wideł ); powłoka może to zrobić wewnętrznie za pomocą rozszerzenia parametrów :
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.
Zauważ, że jeśli stosujesz tę technikę w innych okolicznościach (nie PWD
, ale jakaś inna zmienna zawierająca nazwę katalogu), może być konieczne przycięcie końcowych ukośników. Poniżej używa obsługi extglob bash do pracy nawet z wieloma końcowymi ukośnikami:
dirname=/path/to/somewhere//
shopt -s extglob # enable +(...) glob syntax
result=${dirname%%+(/)} # trim however many trailing slashes exist
result=${result##*/} # remove everything before the last / that still remains
printf '%s\n' "$result"
Alternatywnie bez extglob
:
dirname="/path/to/somewhere//"
result="${dirname%"${dirname##*[!/]}"}" # extglob-free multi-trailing-/ trim
result="${result##*/}" # remove everything before the last /
$PWD
to nazwa wbudowanej zmiennej bash; wszystkie wbudowane nazwy zmiennych są pisane wielkimi literami (aby odróżnić je od zmiennych lokalnych, które zawsze powinny mieć co najmniej jedną małą literę). result=${PWD#*/}
robi nie ocenia się /full/path/to/directory
; zamiast tego usuwa tylko pierwszy element, czyniąc go path/to/directory
; użycie dwóch #
znaków sprawia, że wzór pasuje do zachłannego, dopasowując tyle znaków, ile się da. Przeczytaj stronę rozwijania parametrów, połączoną w odpowiedzi, aby uzyskać więcej.
pwd
nie zawsze jest taki sam jak wartość $PWD
, ze względu na komplikacje wynikające z wejścia cd
przez dowiązania symboliczne, czy bash ma -o physical
ustawioną opcję i tak dalej. Kiedyś szczególnie nieprzyjemnie obchodziło się z obsługą katalogów montowanych automatycznie, gdzie rejestrowanie ścieżki fizycznej zamiast logicznej tworzyłoby ścieżkę, która, jeśli byłaby używana, pozwoliłaby automatycznemu spontanicznemu odinstalowaniu używanego katalogu.
sh
i csh
jeśli chciałeś klawisz Backspace do pracy trzeba było przeczytać całą stty
stronę man, i podobało nam się to!”
Skorzystaj z basename
programu. W twoim przypadku:
% basename "$PWD"
bin
basename
programu? Co jest złego w tej odpowiedzi oprócz pominięcia cytatów?
basename
rzeczywiście jest zewnętrzny program, który robi to, co trzeba, ale działa żadnego zewnętrznego programu do bash, co można zrobić, out-of-the-box przy użyciu tylko wbudowaną funkcjonalność jest głupie, ponosząc wpływ na wydajność ( fork()
, execve()
, wait()
, etc) dla bez powodu.
basename
tutaj nie dotyczą dirname
, ponieważ dirname
ma funkcjonalność, która ${PWD##*/}
tego nie robi - na przykład przekształcanie łańcucha bez ukośników .
. Tak więc, chociaż korzystanie z niego dirname
jako narzędzia zewnętrznego ma narzut związany z wydajnością, ma również funkcjonalność, która pomaga to zrekompensować.
function
kluczowe jest niekompatybilne z POSIX- em bez dodawania wartości ponad standardową składnię, a brak cudzysłowów powodowałby błędy w nazwach katalogów ze spacjami. wdexec() { "./$(basename "$PWD")"; }
może być preferowaną alternatywą.
basename
jest mniej „wydajne”. Ale prawdopodobnie jest bardziej wydajny pod względem produktywności programistów, ponieważ jest łatwy do zapamiętania w porównaniu do brzydkiej składni bash. Więc jeśli to pamiętasz, idź. W przeciwnym razie basename
działa równie dobrze. Czy ktoś kiedykolwiek musiał poprawić „wydajność” skryptu bash i uczynić go bardziej wydajnym?
$ echo "${PWD##*/}"
W pobliżu
echo "${PWD##*/}"
.
name=${PWD##*/}
byłoby na przykład przypisanie jej do zmiennej, byłoby to słuszne i name=$(echo "${PWD##*/}")
błędne (w sensie niepotrzebnej nieefektywności).
Możesz użyć kombinacji pwd i basename. Na przykład
#!/bin/bash
CURRENT=`pwd`
BASENAME=`basename "$CURRENT"`
echo "$BASENAME"
exit;
Co powiesz na grep:
pwd | grep -o '[^/]*$'
pwd | xargs basename
gdy nie .. prawdopodobnie nie jest tak ważny, ale druga odpowiedź jest prostsza i bardziej spójna w różnych środowiskach
Podoba mi się wybrana odpowiedź (Charles Duffy), ale bądź ostrożny, jeśli jesteś w dowiązanym do siebie katalogu i chcesz nazwę docelowego katalogu. Niestety nie sądzę, że można tego dokonać w wyrażeniu rozwijającym jeden parametr, być może się mylę. To powinno działać:
target_PWD=$(readlink -f .)
echo ${target_PWD##*/}
Aby to zobaczyć, eksperyment:
cd foo
ln -s . bar
echo ${PWD##*/}
zgłasza „pasek”
Aby wyświetlić wiodące katalogi ścieżki (bez wywoływania fork-exec z / usr / bin / dirname):
echo ${target_PWD%/*}
To np. Przekształci foo / bar / baz -> foo / bar
readlink -f
jest rozszerzeniem GNU, a zatem nie jest dostępne w BSD (w tym OS X).
echo "$PWD" | sed 's!.*/!!'
Jeśli używasz powłoki Bourne'a lub ${PWD##*/}
nie jest dostępny.
${PWD##*/}
to POSIX sh - obsługuje każdy nowoczesny / bin / sh (w tym myślnik, popiół itp.); aby trafić do rzeczywistego Bourne'a na najnowszym pudełku, musisz być w nieco starszym systemie Solaris. Poza tym - echo "$PWD"
; pominięcie cudzysłowu prowadzi do błędów (jeśli nazwa katalogu zawiera spacje, znaki wieloznaczne itp.).
Zaskakujące, nikt nie wspomniał o tej alternatywie, która wykorzystuje tylko wbudowane polecenia bash:
i="$IFS";IFS='/';set -f;p=($PWD);set +f;IFS="$i";echo "${p[-1]}"
Jako dodatkowy bonus możesz łatwo uzyskać nazwę katalogu nadrzędnego za pomocą:
[ "${#p[@]}" -gt 1 ] && echo "${p[-2]}"
Będą działać na Bash 4.3-alpha lub nowszym.
Posługiwać się:
basename "$PWD"
LUB
IFS=/
var=($PWD)
echo ${var[-1]}
Obróć wewnętrzny separator nazw plików (IFS) z powrotem do spacji.
IFS=
Po IFS jest jedna spacja.
basename $(pwd)
lub
echo "$(basename $(pwd))"
pwd
jest dzielony na ciągi i rozwijany glob przed przekazaniem do basename
.
basename "$(pwd)"
- chociaż jest to bardzo nieefektywne w porównaniu do sprawiedliwego basename "$PWD"
, które samo w sobie jest nieefektywne w porównaniu do używania rozszerzenia parametrów zamiast wywoływania basename
w ogóle.
Aby znaleźć dżokejów takich jak ja:
find $PWD -maxdepth 0 -printf "%f\n"
$PWD
aby "$PWD"
poprawnie obsługiwać nietypowe nazwy katalogów.
zwykle używam tego w skryptach sh
SCRIPTSRC=`readlink -f "$0" || echo "$0"`
RUN_PATH=`dirname "${SCRIPTSRC}" || echo .`
echo "Running from ${RUN_PATH}"
...
cd ${RUN_PATH}/subfolder
możesz użyć tego do automatyzacji rzeczy ...
Działa również poniżej grep z regex,
>pwd | grep -o "\w*-*$"
Po prostu użyj:
pwd | xargs basename
lub
basename "`pwd`"
xargs
Formuła jest nieefektywna i błędna, gdy nazwy katalogów zawierają dosłowne znaki nowej linii lub znaki cudzysłowu, a druga formuła wywołuje pwd
polecenie w podpowłoce zamiast pobierać ten sam wynik za pomocą wbudowanego rozszerzenia zmiennej.
Jeśli chcesz zobaczyć tylko bieżący katalog w obszarze monitu bash, możesz edytować .bashrc
plik w ~
. Zmień \w
na \W
w linii:
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
Uruchom source ~/.bashrc
i wyświetli nazwę katalogu tylko w obszarze monitu.
Patrz: /superuser/60555/show-only-current-directory-name-not-full-path-on-bash-prompt
Zdecydowanie wolę używać gbasename
, który jest częścią jądra GNU.
basename
tam nazywa . Jest to zwykle wywoływane tylko gbasename
na MacOS i innych platformach, które w przeciwnym razie są dostarczane z basenemame bez GNU.
Następujące polecenia spowodują wydrukowanie bieżącego katalogu roboczego w skrypcie bash.
pushd .
CURRENT_DIR="`cd $1; pwd`"
popd
echo $CURRENT_DIR
$1
zawiera bieżący katalog roboczy. (2) pushd
I popd
nie służą tutaj, ponieważ wszystko w backstikach odbywa się w podpowłoce - więc nie może wpływać na katalog powłoki nadrzędnej na początek. (3) Używanie "$(cd "$1"; pwd)"
byłoby bardziej czytelne i odporne na nazwy katalogów z białymi znakami.