মূলত আমাকে শেল স্ক্রিপ্ট ফাইলের অবস্থান সম্পর্কিত পাথ দিয়ে স্ক্রিপ্ট চালানো দরকার, আমি কীভাবে বর্তমান ডিরেক্টরিটিকে একই ডিরেক্টরিতে পরিবর্তন করতে পারি যেখানে স্ক্রিপ্ট ফাইলটি থাকে?
মূলত আমাকে শেল স্ক্রিপ্ট ফাইলের অবস্থান সম্পর্কিত পাথ দিয়ে স্ক্রিপ্ট চালানো দরকার, আমি কীভাবে বর্তমান ডিরেক্টরিটিকে একই ডিরেক্টরিতে পরিবর্তন করতে পারি যেখানে স্ক্রিপ্ট ফাইলটি থাকে?
উত্তর:
বাশ-এ, আপনার যা প্রয়োজন তা পাওয়া উচিত:
#!/usr/bin/env bash
BASEDIR=$(dirname "$0")
echo "$BASEDIR"
readlink
পাশাপাশি ব্যবহার করতে হবে (নীচে আল এর উত্তর দেখুন)
$BASH_SOURCE
পরিবর্তে ব্যবহার করা নিরাপদ $0
, কারণ $0
স্ক্রিপ্টটি সর্বদা আহ্বান করার পথ থাকে না যেমন যেমন কোনও স্ক্রিপ্ট যখন 'সোর্সিং' করা হয়।
$BASH_SOURCE
বাশ-নির্দিষ্ট, প্রশ্নটি সাধারণভাবে শেল স্ক্রিপ্ট সম্পর্কে।
CUR_PATH=$(pwd)
বা pwd
বর্তমান ডিরেক্টরিটি ফিরিয়ে দিন (যা স্ক্রিপ্টগুলির পিতা মাতা হতে হবে না)!
$BASH_SOURCE
এবং এটি আমার যা প্রয়োজন তা ফিরিয়ে দেয়। আমার স্ক্রিপ্ট অন্য স্ক্রিপ্ট থেকে আহবান করা হয়, এবং $0
আয় .
যখন $BASH_SOURCE
আয় অধিকার সাব (আমার ক্ষেত্রে scripts
)।
মূল পোস্টটিতে সমাধান রয়েছে (প্রতিক্রিয়াগুলি উপেক্ষা করুন, তারা দরকারী কিছু যোগ করেন না)। আকর্ষণীয় কাজ readlink
বিকল্প ইউনিক্স কমান্ড বিকল্প সহ সম্পন্ন করা হয় -f
। স্ক্রিপ্টটি যখন কোনও পরম্পরা এবং তেমনি কোনও আপেক্ষিক পথ দ্বারা ডাকা হয় Works
বাশ, শ, ক্ষের জন্য:
#!/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 এর জন্য, সিএসএস:
#!/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
আরও দেখুন: https://stackoverflow.com/a/246128/59087
readlink
। এজন্য আমি পুশড / পপড (ব্যাশের জন্য বিল্ট-ইনস) ব্যবহার করার পরামর্শ দিয়েছি।
-f
বিকল্প readlink
OS X এর (লায়ন) এবং সম্ভবত বাসদ উপর ভিন্ন কিছু নয়। stackoverflow.com/questions/1055671/...
-f
ওএস এক্সে মোটেও সমর্থন করা যায় না (সিংহ হিসাবে); সেখানে আপনি সেক্ষেত্রে -f
সর্বাধিক এক স্তরের ইন্ডিয়ারেশনের সমাধানের জন্য ড্রপ করতে পারেন , যেমন pushd "$(dirname "$(readlink "$BASH_SOURCE" || echo "$BASH_SOURCE")")"
, বা আপনি লিঙ্কযুক্ত পোস্টে প্রদর্শিত আপনার নিজস্ব রিকার্সিভ সিলেমিং-নিম্নলিখিত স্ক্রিপ্টটি রোল করতে পারেন।
sh /some/other/directory/script.sh)
, এক্ষেত্রে .
আপনার পিডব্লিউড হবে, না/some/other/directory
একটি উত্তরের পূর্বের মন্তব্য এটি বলেছিল, তবে অন্য সমস্ত উত্তরগুলির মধ্যে এটি মিস করা সহজ।
ব্যাশ ব্যবহার করার সময়:
echo this file: "$BASH_SOURCE"
echo this dir: "$(dirname "$BASH_SOURCE")"
dirname "$BASH_SOURCE"
পরিবর্তে $ BASH_SOURCE এ স্থানগুলি হ্যান্ডেল করার জন্য আপনার ব্যবহার করা উচিত ।
"$(dirname "${BASH_SOURCE[0]}")"
ধরে নিচ্ছি আপনি ব্যাশ ব্যবহার করছেন
#!/bin/bash
current_dir=$(pwd)
script_dir=$(dirname $0)
echo $current_dir
echo $script_dir
এই স্ক্রিপ্টটিতে আপনার যে ডিরেক্টরিটি রয়েছে সেটিকে মুদ্রণ করা উচিত এবং তারপরে ডিরেক্টরিটি স্ক্রিপ্টের মধ্যে রয়েছে। উদাহরণস্বরূপ, /
স্ক্রিপ্টটির মাধ্যমে এটিকে কল করার সময় /home/mez/
, এটি আউটপুট হয়
/
/home/mez
মনে রাখবেন, কমান্ডের আউটপুট থেকে ভেরিয়েবলগুলি বরাদ্দ করার সময়, কমান্ডটি ভিতরে लपेटুন $(
এবং )
- বা আপনি পছন্দসই আউটপুট পাবেন না।
আপনি যদি ব্যাশ ব্যবহার করছেন ....
#!/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
সঙ্গে cd $(dirname "${0}")
এবং cd -
এটি অন্যান্য শাঁস কাজ, যদি তারা একটি আছে করতে pwd -L
।
যেমন মারকো পরামর্শ দেয়:
BASEDIR=$(dirname $0)
echo $BASEDIR
স্ক্রিপ্ট যেখানে থাকে সেই একই ডিরেক্টরি থেকে আপনি স্ক্রিপ্টটি সম্পাদন না করা হলে এটি কাজ করে, যেখানে আপনি 'এর মান পান।'
এই সমস্যাটি ব্যবহার করতে:
current_dir=$(pwd)
script_dir=$(dirname $0)
if [ $script_dir = '.' ]
then
script_dir="$current_dir"
fi
স্ক্রিপ্ট ডিরেক্টরিটি উল্লেখ করতে আপনি এখন আপনার স্ক্রিপ্ট জুড়ে চলক কারেন্ট_ডির ব্যবহার করতে পারেন। তবে এটিতে এখনও সিমলিংকের সমস্যা থাকতে পারে।
এই প্রশ্নের সেরা উত্তরটি এখানে দেওয়া হয়েছিল:
একটি বাশ স্ক্রিপ্টের সূত্রের ডিরেক্টরি ভিতরে থেকে পাওয়া
এবং এটা করা হয়:
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
ওয়ান-লাইনার যা স্ক্রিপ্টের যেখানেই ডাকা হচ্ছে না কেন তার সম্পূর্ণ ডিরেক্টরি নাম দেবে।
এটি কীভাবে কাজ করে তা বুঝতে আপনি নীচের স্ক্রিপ্টটি কার্যকর করতে পারেন:
#!/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'"
আসুন এটি একটি পসিক্স অনলাইনার করুন:
a="/$0"; a=${a%/*}; a=${a#/}; a=${a:-.}; BASEDIR=$(cd "$a"; pwd)
বিএসডি সহ অনেক বোর্ন-সামঞ্জস্যপূর্ণ শেলগুলির উপর পরীক্ষিত।
আমি যতদূর জানি আমি লেখক এবং আমি এটি সর্বজনীন ডোমেনে রেখেছি। আরও তথ্যের জন্য দেখুন: https://www.jasan.tk/posts/2017-05-11-posix_shell_dirname_replacement/
cd: too many arguments
যদি পথে ফাঁকা থাকে এবং ফিরে আসে $PWD
। (একটি সুস্পষ্ট ফিক্স, তবে প্রকৃতপক্ষে কতগুলি প্রান্তের কেস রয়েছে তা কেবল দেখায়)
BASE_DIR="$(cd "$(dirname "$0")"; pwd)";
echo "BASE_DIR => $BASE_DIR"
আপনি যদি সত্যিকারের স্ক্রিপ্ট ডিরেক্টরিটি পেতে চান (আপনি সিম্পলিংক ব্যবহার করছেন বা সরাসরি স্ক্রিপ্টটি আহ্বান করছেন তা নির্বিশেষে), চেষ্টা করুন:
BASEDIR=$(dirname $(realpath "$0"))
echo "$BASEDIR"
এটি লিনাক্স এবং ম্যাকোস উভয় ক্ষেত্রেই কাজ করে। আমি এখানে কাউকে উল্লেখ উল্লেখ করতে পারে না realpath
। এই পদ্ধতির কোনও ত্রুটি আছে কিনা তা নিশ্চিত নয়।
ম্যাকোজে, আপনাকে coreutils
ব্যবহারের জন্য ইনস্টল করতে হবে realpath
। উদাহরণ: brew install coreutils
।
সূচনা
এই উত্তরটি এই থ্রেডের অত্যন্ত ভাঙ্গা তবে মর্মাহতভাবে শীর্ষে দেওয়া ভোটের উত্তরকে সংশোধন করে (দ্যমারকো দ্বারা লিখিত):
#!/usr/bin/env bash
BASEDIR=$(dirname "$0")
echo "$BASEDIR"
এটি নিজের কাজ করে না কেন "$ 0" নামটি ব্যবহার করে?
ডায়ারনাম $ 0 কেবল তখনই কাজ করবে যদি ব্যবহারকারী খুব নির্দিষ্ট উপায়ে স্ক্রিপ্ট চালু করে। আমি বেশ কয়েকটি পরিস্থিতি সন্ধান করতে পেরেছিলাম যেখানে এই উত্তরটি ব্যর্থ হয় এবং স্ক্রিপ্টটি ক্র্যাশ করে।
সবার আগে, আসুন বুঝতে পারি যে এই উত্তরটি কীভাবে কাজ করে। তিনি স্ক্রিপ্ট ডিরেক্টরিটি পেয়ে যাচ্ছেন
dirname "$0"
$ 0 কমান্ডের প্রথম অংশটি স্ক্রিপ্টটি কল করে প্রতিনিধিত্ব করে (এটি মূলত যুক্তি ছাড়াই ইনপুটযুক্ত কমান্ড:
/some/path/./script argument1 argument2
$ 0 = "/ কিছু / পথ /./ স্ক্রিপ্ট"
ডায়ারনামটি মূলত সর্বশেষ / একটি স্ট্রিংয়ের সন্ধান করে এবং সেখানে এটি কেটে দেয়। সুতরাং আপনি যদি:
dirname /usr/bin/sha256sum
আপনি পাবেন: / usr / বিন
এই উদাহরণটি ভালভাবে কাজ করে কারণ / usr / bin / sha256sum সঠিকভাবে ফর্ম্যাটেড পাথ তবে
dirname "/some/path/./script"
ভাল কাজ করবে না এবং আপনাকে দিতে হবে:
BASENAME="/some/path/." #which would crash your script if you try to use it as a path
বলুন যে আপনি আপনার স্ক্রিপ্টের মতো একই গানে রয়েছেন এবং আপনি এটিকে এই আদেশ দিয়ে লঞ্চ করছেন
./script
এই পরিস্থিতিতে $ 0 হবে। / স্ক্রিপ্ট এবং dirname $ 0 দেবে:
. #or BASEDIR=".", again this will crash your script
ব্যবহার:
sh script
সম্পূর্ণ পথ ইনপুট না করেও একটি বেসড = "দেবে।"
আপেক্ষিক ডিরেক্টরি ব্যবহার:
../some/path/./script
একটি শিরোনাম $ 0 দেয়:
../some/path/.
আপনি যদি / কোনও ডিরেক্টরিতে থাকেন এবং আপনি এই পদ্ধতিতে স্ক্রিপ্টটি কল করেন (শুরুতে / আবার অনুপস্থিতির অনুপস্থিতিতে নোট করুন):
path/./script.sh
আপনি dirname $ 0 এর জন্য এই মানটি পাবেন:
path/.
এবং ./path/./script (আপেক্ষিক পথের অন্য রূপ) দেয়:
./path/.
কেবলমাত্র দুটি পরিস্থিতিতে যেখানে $ 0 ভিত্তিক কাজ করবে তা হ'ল ব্যবহারকারী যদি স্ক্রিপ্ট আরম্ভ করতে sh বা স্পর্শ ব্যবহার করেন কারণ উভয়ের ফলাফল $ 0:
$0=/some/path/script
যা আপনাকে এমন একটি পথ দেবে যা আপনি নাম দিয়ে ব্যবহার করতে পারেন।
সমাধান
আপনি উপরোক্ত উল্লিখিত অবস্থার প্রত্যেকটির জন্য অ্যাকাউন্ট তৈরি করতে এবং সনাক্ত করতে এবং যদি এটির উদ্ভব হয় তবে তার জন্য একটি স্থিরতা প্রয়োগ করুন:
#!/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
এই ওয়ান লাইনারটি শেল স্ক্রিপ্টটি কোথায় তা বলে, আপনি এটি চালিয়েছেন কিনা বা আপনি এটি উত্সাহিত করেছেন তাতে কিছু আসে যায় না । এছাড়াও, এটি জড়িত যে কোনও প্রতীকী লিঙ্কগুলি সমাধান করে, যদি এটি হয়:
dir=$(dirname $(test -L "$BASH_SOURCE" && readlink -f "$BASH_SOURCE" || echo "$BASH_SOURCE"))
যাইহোক, আমি মনে করি আপনি / বিন / ব্যাশ ব্যবহার করছেন ।
প্রো এর এবং কন এর সাথে সামান্য বিচিত্র উদ্দেশ্যগুলি (যা সম্ভবত প্রত্যেকের জন্য বর্ণিত হওয়া উচিত) সহ সমস্ত উত্তর, সমস্ত প্রশংসনীয়। এখানে আরও একটি সমাধান রয়েছে যা সমস্ত সিস্টেমের মধ্যে সমস্ত ব্যাশে (ব্যাশ সংস্করণ, readlink
বা pwd
বিকল্পগুলি সম্পর্কে কোনও অনুমান নয়) পরিষ্কার এবং কাজ করা উভয়ের একটি প্রাথমিক উদ্দেশ্য পূরণ করে এবং আপনি যা করতে চান তা যুক্তিসঙ্গত করে (যেমন, সিমলিংকগুলি সমাধান করা একটি) আকর্ষণীয় সমস্যা, তবে সাধারণত আপনি যা চান তা নয়), পাথের ফাঁকা জায়গাগুলির মতো প্রান্তের কেসগুলি হ্যান্ডেল করে, কোনও ত্রুটি উপেক্ষা করে এবং যদি কোনও সমস্যা থাকে তবে বুদ্ধিমান ডিফল্ট ব্যবহার করে।
প্রতিটি উপাদান একটি পৃথক ভেরিয়েবলে সংরক্ষণ করা হয় যা আপনি স্বতন্ত্রভাবে ব্যবহার করতে পারেন:
# 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)"
নীল বর্ণের উত্তর দ্বারা অনুপ্রাণিত
read < <(readlink -f $0 | xargs dirname)
cd $REPLY
এটি কৌশলটি করা উচিত:
echo `pwd`/`dirname $0`
এটি কীভাবে আহ্বান করা হয়েছিল এবং সিডব্লিউডির উপর নির্ভর করে এটি দেখতে কুরুচিপূর্ণ হতে পারে তবে আপনাকে কোথায় যেতে হবে তা পাওয়া উচিত (বা স্ট্রিংটি কীভাবে দেখতে পারা যায় তবে আপনি তা মুছে ফেলতে পারেন)।
`pwd`/`dirname $0`
তবে তবুও এটি প্রতীকগুলিতে ব্যর্থ হতে পারে