Temelde ben komut dosyasını kabuk komut dosyası dosya konumu ile ilgili yolları ile çalıştırmak gerekir, nasıl geçerli dizini komut dosyası bulunduğu nerede aynı dizine değiştirebilirsiniz?
Temelde ben komut dosyasını kabuk komut dosyası dosya konumu ile ilgili yolları ile çalıştırmak gerekir, nasıl geçerli dizini komut dosyası bulunduğu nerede aynı dizine değiştirebilirsiniz?
Yanıtlar:
Bash'de ihtiyacınız olan şeyi şu şekilde almalısınız:
#!/usr/bin/env bash
BASEDIR=$(dirname "$0")
echo "$BASEDIR"
readlink
(aşağıdaki
$BASH_SOURCE
yerine kullanmak daha güvenlidir $0
, çünkü $0
her zaman bir komut dosyasının 'kaynaklanması' gibi çağrılan komut dosyasının yolunu içermez.
$BASH_SOURCE
Bash'a özgüdür, soru genel olarak kabuk betiği ile ilgilidir.
CUR_PATH=$(pwd)
veya pwd
geçerli dizini döndürür (komut dosyasının üst dizini olması gerekmez)!
$BASH_SOURCE
ben ne gerek döndürür. Benim komut dosyası başka bir komut dosyası aradı, ediliyor $0
döner .
iken $BASH_SOURCE
döner (benim durumumda sağ alt dizin scripts
).
Orijinal gönderi çözümü içerir (yanıtları yoksayın, yararlı bir şey eklemezler). İlginç iş readlink
seçeneği ile belirtilen unix komutu ile yapılır -f
. Komut dosyası hem mutlak hem de göreli bir yolla çağrıldığında çalışır.
Bash, sh, ksh için:
#!/bin/bash
# Absolute path to this script, e.g. /home/user/bin/foo.sh
SCRIPT=$(readlink -f "$0")
# Absolute path this script is in, thus /home/user/bin
SCRIPTPATH=$(dirname "$SCRIPT")
echo $SCRIPTPATH
Tcsh, csh için:
#!/bin/tcsh
# Absolute path to this script, e.g. /home/user/bin/foo.csh
set SCRIPT=`readlink -f "$0"`
# Absolute path this script is in, thus /home/user/bin
set SCRIPTPATH=`dirname "$SCRIPT"`
echo $SCRIPTPATH
Ayrıca bakınız: https://stackoverflow.com/a/246128/59087
readlink
. Bu yüzden pushd / popd (bash için yerleşik) kullanmanızı tavsiye ettim.
-f
Seçeneği readlink
muhtemelen OS X (Lion) ve BSD üzerinde farklı bir şey yok. stackoverflow.com/questions/1055671/…
-f
OS X'te hiç desteklenmiyor (Lion'dan itibaren); orada -f
, örneğin en fazla bir dolaylı seviyeyi çözmeyle yapmak için bırakabilir pushd "$(dirname "$(readlink "$BASH_SOURCE" || echo "$BASH_SOURCE")")"
veya bağlantılı yayında gösterildiği gibi kendi özyinelemeli symlink-takip komut dosyanızı yuvarlayabilirsiniz.
sh /some/other/directory/script.sh)
, bu durumda .
pwd'niz olurdu, değil/some/other/directory
Bir cevap üzerine daha önce yapılan bir yorumda bunu söyledi, ancak diğer tüm cevapları kaçırmak kolaydır.
Bash kullanırken:
echo this file: "$BASH_SOURCE"
echo this dir: "$(dirname "$BASH_SOURCE")"
dirname "$BASH_SOURCE"
yerine $ BASH_SOURCE içindeki boşlukları işlemek için kullanmalısınız .
"$(dirname "${BASH_SOURCE[0]}")"
Bash kullandığınızı varsayarsak
#!/bin/bash
current_dir=$(pwd)
script_dir=$(dirname $0)
echo $current_dir
echo $script_dir
Bu komut dosyasının içinde bulunduğunuz dizini ve sonra komut dosyasının içinde bulunduğu dizini yazdırması gerekir. Örneğin /
, komut dosyası ile çağrıldığında /home/mez/
çıktı verir
/
/home/mez
Unutmayın, bir komutun çıkışından değişkenler atarken, komutu içine sarın $(
ve )
- veya istediğiniz çıktıyı alamayacağınızı unutmayın.
Eğer bash kullanıyorsanız ....
#!/bin/bash
pushd $(dirname "${0}") > /dev/null
basedir=$(pwd -L)
# Use "pwd -P" for the path without links. man bash for more info.
popd > /dev/null
echo "${basedir}"
pushd
/ popd
ile cd $(dirname "${0}")
ve cd -
onlar varsa, diğer kabukları üzerinde çalışmasını sağlamak için pwd -L
.
Marko'nun önerdiği gibi:
BASEDIR=$(dirname $0)
echo $BASEDIR
Komut dosyasını, komut dosyasının bulunduğu aynı dizinden yürütmediğiniz sürece çalışır, bu durumda '.' Değeri alırsınız.
Bu sorunu çözmek için şunu kullanın:
current_dir=$(pwd)
script_dir=$(dirname $0)
if [ $script_dir = '.' ]
then
script_dir="$current_dir"
fi
Artık komut dosyası dizinine başvurmak için komut dosyanız boyunca current_dir değişkenini kullanabilirsiniz. Ancak bunun yine de bağlantı bağlantısı sorunu olabilir.
Bu soru için en iyi cevap burada cevaplandı:
Bir Bash betiğinin kaynak dizinini içeriden almak
Ve budur:
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
Nereden çağrılırsa çağrılsın size komut dosyasının tam dizin adını verecek tek satırlık.
Nasıl çalıştığını anlamak için aşağıdaki komut dosyasını yürütebilirsiniz:
#!/bin/bash
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
TARGET="$(readlink "$SOURCE")"
if [[ $TARGET == /* ]]; then
echo "SOURCE '$SOURCE' is an absolute symlink to '$TARGET'"
SOURCE="$TARGET"
else
DIR="$( dirname "$SOURCE" )"
echo "SOURCE '$SOURCE' is a relative symlink to '$TARGET' (relative to '$DIR')"
SOURCE="$DIR/$TARGET" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
fi
done
echo "SOURCE is '$SOURCE'"
RDIR="$( dirname "$SOURCE" )"
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
if [ "$DIR" != "$RDIR" ]; then
echo "DIR '$RDIR' resolves to '$DIR'"
fi
echo "DIR is '$DIR'"
Bir POSIX oneliner yapalım:
a="/$0"; a=${a%/*}; a=${a#/}; a=${a:-.}; BASEDIR=$(cd "$a"; pwd)
BSD olanlar dahil Bourne uyumlu birçok mermi üzerinde test edildi.
Bildiğim kadarıyla ben yazarım ve bunu kamu malı haline getirdim. Daha fazla bilgi için bkz. Https://www.jasan.tk/posts/2017-05-11-posix_shell_dirname_replacement/
cd: too many arguments
eğer yoldaki boşluklar ve döner $PWD
. (bariz bir düzeltme, ama aslında kaç tane kenar durum olduğunu gösterir)
BASE_DIR="$(cd "$(dirname "$0")"; pwd)";
echo "BASE_DIR => $BASE_DIR"
Gerçek komut dosyası dizinini almak istiyorsanız (komut dosyasını bir symlink kullanarak mı yoksa doğrudan mı çağırdığınızdan bağımsız olarak) şunu deneyin:
BASEDIR=$(dirname $(realpath "$0"))
echo "$BASEDIR"
Bu hem linux hem de macOS üzerinde çalışır. Burada kimsenin bahsettiğini göremedim realpath
. Bu yaklaşımda herhangi bir dezavantaj olup olmadığından emin değilim.
macOS'ta coreutils
kullanmak için yüklemeniz gerekir realpath
. Ör: brew install coreutils
.
GİRİŞ
Bu cevap , bu konunun çok kırık ama şok edici bir şekilde en çok oy alan cevabını düzeltir (TheMarko tarafından yazılmıştır):
#!/usr/bin/env bash
BASEDIR=$(dirname "$0")
echo "$BASEDIR"
KENDİ ÜZERİNE "$ 0" dirname NEDEN ÇALIŞMIYOR?
dirname $ 0 yalnızca kullanıcı komut dosyasını çok özel bir şekilde başlatırsa çalışır. Bu cevabın başarısız olduğu ve senaryoyu çökerttiği birkaç durum bulabildim.
Her şeyden önce, bu cevabın nasıl çalıştığını anlayalım. Senaryo dizinini yaparak
dirname "$0"
$ 0 , komut dosyasını çağıran komutun ilk bölümünü temsil eder (temelde argümanlar olmadan girilen komuttur:
/some/path/./script argument1 argument2
0 $ = "/ bir / yol /./ komut dosyası"
dirname temelde bir dizede son / dizeyi bulur ve orada keser. Yani eğer yaparsanız:
dirname /usr/bin/sha256sum
alacaksınız: / usr / bin
/ Usr / bin / sha256sum düzgün biçimlendirilmiş bir yol olduğu için bu örnek iyi çalışıyor ancak
dirname "/some/path/./script"
iyi çalışmaz ve size:
BASENAME="/some/path/." #which would crash your script if you try to use it as a path
Senaryonuzla aynı direkte olduğunuzu ve bunu bu komutla başlattığınızı varsayalım
./script
Bu durumda 0 $ olur ./script ve $ 0 dizin adı verir:
. #or BASEDIR=".", again this will crash your script
Kullanımı:
sh script
Tam yol girilmeden bir BASEDIR = "verecektir."
Göreli dizinleri kullanma:
../some/path/./script
0 $ değerinde bir dirname verir:
../some/path/.
/ Some dizinindeyseniz ve komut dosyasını bu şekilde çağırıyorsanız (başlangıçta / bulunmadığını, yine göreceli bir yol olduğunu unutmayın):
path/./script.sh
Bu değeri $ 0 dizin adı için alacaksınız:
path/.
ve ./path/./script (göreceli yolun başka bir biçimi) şunları verir:
./path/.
0 $ temelli çalışmanın yalnızca iki durumu , kullanıcının bir komut dosyası başlatmak için sh veya touch kullanmasıdır, çünkü her ikisi de 0 $ ile sonuçlanır:
$0=/some/path/script
size dirname ile kullanabileceğiniz bir yol verecektir.
ÇÖZÜM
Yukarıda belirtilen durumların her birini hesaba katar ve tespit eder ve ortaya çıkarsa bir düzeltme uygularsınız:
#!/bin/bash
#this script will only work in bash, make sure it's installed on your system.
#set to false to not see all the echos
debug=true
if [ "$debug" = true ]; then echo "\$0=$0";fi
#The line below detect script's parent directory. $0 is the part of the launch command that doesn't contain the arguments
BASEDIR=$(dirname "$0") #3 situations will cause dirname $0 to fail: #situation1: user launches script while in script dir ( $0=./script)
#situation2: different dir but ./ is used to launch script (ex. $0=/path_to/./script)
#situation3: different dir but relative path used to launch script
if [ "$debug" = true ]; then echo 'BASEDIR=$(dirname "$0") gives: '"$BASEDIR";fi
if [ "$BASEDIR" = "." ]; then BASEDIR="$(pwd)";fi # fix for situation1
_B2=${BASEDIR:$((${#BASEDIR}-2))}; B_=${BASEDIR::1}; B_2=${BASEDIR::2}; B_3=${BASEDIR::3} # <- bash only
if [ "$_B2" = "/." ]; then BASEDIR=${BASEDIR::$((${#BASEDIR}-1))};fi #fix for situation2 # <- bash only
if [ "$B_" != "/" ]; then #fix for situation3 #<- bash only
if [ "$B_2" = "./" ]; then
#covers ./relative_path/(./)script
if [ "$(pwd)" != "/" ]; then BASEDIR="$(pwd)/${BASEDIR:2}"; else BASEDIR="/${BASEDIR:2}";fi
else
#covers relative_path/(./)script and ../relative_path/(./)script, using ../relative_path fails if current path is a symbolic link
if [ "$(pwd)" != "/" ]; then BASEDIR="$(pwd)/$BASEDIR"; else BASEDIR="/$BASEDIR";fi
fi
fi
if [ "$debug" = true ]; then echo "fixed BASEDIR=$BASEDIR";fi
Bu tek satır, kabuk komut dosyasının nerede olduğunu söyler, çalıştırdığınız veya kaynakladığınız önemli değildir . Ayrıca, söz konusu ise, söz konusu sembolik bağlantıları çözer:
dir=$(dirname $(test -L "$BASH_SOURCE" && readlink -f "$BASH_SOURCE" || echo "$BASH_SOURCE"))
Bu arada, / bin / bash kullandığınızı düşünüyorum .
Pek çok yanıt, hepsi akla yatkın, her biri pro ve con'un ve biraz farklı hedefleri (muhtemelen her biri için belirtilmelidir). Burada, tüm sistemlerde, hem açık hem de tüm sistemlerde çalışmanın (bash sürümleri veya readlink
veya pwd
seçeneklerle ilgili herhangi bir varsayım yok) birincil amacını karşılayan ve gerçekleşmesini beklediğinizi makul bir şekilde yapan (ör. Sembolik bağlantıları çözmek) ilginç bir sorun, ancak genellikle aslında istediğiniz şey değildir), yollardaki boşluklar gibi kenar durumlarını ele alın, herhangi bir hatayı yok sayar ve herhangi bir sorun varsa aklı başında bir varsayılan kullanır.
Her bileşen ayrı ayrı kullanabileceğiniz ayrı bir değişkende saklanır:
# script path, filename, directory
PROG_PATH=${BASH_SOURCE[0]} # this script's name
PROG_NAME=${PROG_PATH##*/} # basename of script (strip path)
PROG_DIR="$(cd "$(dirname "${PROG_PATH:-$PWD}")" 2>/dev/null 1>&2 && pwd)"
Blueyed'in cevabından ilham aldı
read < <(readlink -f $0 | xargs dirname)
cd $REPLY
Hile yapmalı:
echo `pwd`/`dirname $0`
Nasıl çağrıldığına ve cwd'ye bağlı olarak çirkin görünebilir, ancak gitmeniz gereken yere ulaşmanızı sağlar (veya nasıl göründüğünü önemsiyorsanız dizeyi değiştirebilirsiniz).
`pwd`/`dirname $0`
ama yine de semboller başarısız olabilir