bash - files - read ubuntu partition from windows 7




الحصول على الدليل المصدر للبرنامج النصي Bash من الداخل (20)

أود استخدام شيء مثل هذا:

# retrieve the full pathname of the called script
scriptPath=$(which $0)

# check whether the path is a link or not
if [ -L $scriptPath ]; then

    # it is a link then retrieve the target path and get the directory name
    sourceDir=$(dirname $(readlink -f $scriptPath))

else

    # otherwise just get the directory name of the script path
    sourceDir=$(dirname $scriptPath)

fi

كيف يمكنني الحصول على مسار الدليل الذي يوجد فيه نص Bash ، داخل هذا النص البرمجي؟

على سبيل المثال ، لنفترض أنني أريد استخدام برنامج Bash النصي كمشغل لتطبيق آخر. أريد تغيير دليل العمل إلى المكان الذي يوجد فيه نص Bash ، لذا يمكنني العمل على الملفات الموجودة في هذا الدليل ، مثل:

$ ./application

اجابة قصيرة:

`dirname $0`

أو ( preferably ):

$(dirname "$0")

الأمر dirname هو أبسط ، ببساطة تحليل المسار إلى اسم الملف من المتغير $ 0 (اسم البرنامج النصي):

dirname "$0"

ولكن ، كما أشار ب مات ، فإن المسار الذي يتم إرجاعه يختلف باختلاف طريقة استدعاء البرنامج النصي. لا يقوم pwd بالمهمة لأن ذلك يخبرك فقط ما هو الدليل الحالي ، وليس ما الدليل الذي يتواجد فيه البرنامج النصي. بالإضافة إلى ذلك ، إذا تم تنفيذ ارتباط رمزي إلى نص برمجي ، فستحصل على مسار (ربما نسبي) إلى مكان وجود الرابط ، وليس النص الفعلي.

ذكر البعض الآخر أمر readlink ، ولكن في أبسط الأمور ، يمكنك استخدام:

dirname "$(readlink -f "$0")"

سوف يحل readlink مسار البرنامج النصي إلى مسار مطلق من جذر نظام الملفات. لذلك ، سيتم حل أي مسارات تحتوي على نقاط فردية أو مزدوجة ، و / أو التيلدز و / أو الروابط الرمزية إلى المسار الكامل.

هنا هو برنامج نصي يدل على كل من هذه ، whatdir.sh:

#!/bin/bash
echo "pwd: `pwd`"
echo "\$0: $0"
echo "basename: `basename $0`"
echo "dirname: `dirname $0`"
echo "dirname/readlink: $(dirname $(readlink -f $0))"

تشغيل هذا البرنامج النصي في ديتر منزلي ، باستخدام مسار نسبي:

>>>$ ./whatdir.sh 
pwd: /Users/phatblat
$0: ./whatdir.sh
basename: whatdir.sh
dirname: .
dirname/readlink: /Users/phatblat

مرة أخرى ، ولكن باستخدام المسار الكامل للبرنامج النصي:

>>>$ /Users/phatblat/whatdir.sh 
pwd: /Users/phatblat
$0: /Users/phatblat/whatdir.sh
basename: whatdir.sh
dirname: /Users/phatblat
dirname/readlink: /Users/phatblat

الآن تغيير الدلائل:

>>>$ cd /tmp
>>>$ ~/whatdir.sh 
pwd: /tmp
$0: /Users/phatblat/whatdir.sh
basename: whatdir.sh
dirname: /Users/phatblat
dirname/readlink: /Users/phatblat

وأخيرًا ، استخدم رابطًا رمزيًا لتنفيذ النص البرمجي:

>>>$ ln -s ~/whatdir.sh whatdirlink.sh
>>>$ ./whatdirlink.sh 
pwd: /tmp
$0: ./whatdirlink.sh
basename: whatdirlink.sh
dirname: .
dirname/readlink: /Users/phatblat

حاولت كل واحد من هؤلاء ولم يعمل أي منهم. كان أحدهم مقربًا جدًا ولكن كان به خطأ صغير حطمه بشدة ؛ نسوا التفاف المسار في علامات اقتباس.

كما يفترض الكثير من الناس أنك تقوم بتشغيل البرنامج النصي من shell حتى تنسي عند فتح برنامج نصي جديد يتم تعيينه لمنزلك.

جرب هذا الدليل للحجم:

/ var / لا أحد / الفكر / حول الفضاءات / في الدليل / الاسم / وهنا إليك file.text

هذا يجعل الأمر صحيحًا بصرف النظر عن كيفية أو مكان تشغيله.

#!/bin/bash
echo "pwd: `pwd`"
echo "\$0: $0"
echo "basename: `basename "$0"`"
echo "dirname: `dirname "$0"`"

إذن ، لجعلها مفيدة فعلاً ، إليك كيفية تغيير دليل البرنامج النصي الجاري تشغيله:

cd "`dirname "$0"`"

امل ان يساعد


لقد قمت بمقارنة العديد من الإجابات المقدمة ، والتوصل إلى بعض الحلول الصغيرة. يبدو أن هذه الأمور تتعامل مع جميع حالات الحواف المجنونة التي تنشأ عن مزيجك المفضل من:

  • المسارات المطلقة أو المسارات النسبية
  • الملف وصلات الدليل لينة
  • استدعاء كنص مكتوب أو script bash script أو bash -c script أو source script أو . script . script
  • المساحات ، علامات التبويب ، newlines ، unicode ، إلخ في الدلائل و / أو اسم الملف
  • أسماء الملفات التي تبدأ بواصلة

إذا كنت تعمل من Linux ، فيبدو أن استخدام مقبض proc هو أفضل حل لتحديد مصدر الحل الكامل للبرنامج النصي الجاري تشغيله حاليًا (في جلسة تفاعلية ، يشير الارتباط إلى /dev/pts/X المعني):

resolved="$(readlink /proc/$$/fd/255 && echo X)" && resolved="${resolved%$'\nX'}"

يحتوي هذا على القليل من القبح ، لكن الإصلاح مضغوط وسهل الفهم. نحن لا نستخدم الأعداد الأولية من bash فقط ، لكنني على ما يرام لأن readlink يبسط المهمة بشكل كبير. يضيف echo X علامة X إلى نهاية السلسلة المتغيرة بحيث لا يتم تناول أي مسافة بيضاء لاحقة في اسم الملف ، ويتخلص استبدال المعلمة ${VAR%X} في نهاية السطر من X ولأن readlink يضيف سطر جديد خاص بها (والذي عادة ما يؤكل في استبدال الأمر إن لم يكن لخداعنا السابق) ، يجب علينا التخلص منه أيضًا. يتم إنجاز ذلك بسهولة باستخدام نظام $'' quote $'' ، والذي يتيح لنا استخدام تسلسلات الهروب مثل \n لتمثيل الخطوط الجديدة (وهذا أيضًا هو كيف يمكنك بسهولة إنشاء ملفات وملفات محددة بشكل خادع).

يجب أن يغطي ما سبق احتياجاتك لتحديد موقع النص الجاري قيد التشغيل حاليًا على نظام التشغيل Linux ، ولكن إذا لم يكن لديك نظام ملفات proc تحت تصرفك ، أو إذا كنت تحاول تحديد موقع المسار الذي تمت معالجته بشكل كامل من بعض الملفات الأخرى ، فربما تكون أنت ' ليرة لبنانية العثور على التعليمات البرمجية أدناه مفيدة. انها مجرد تعديل طفيف من بطانة واحدة أعلاه. إذا كنت تلهو بأسماء / أسماء ملفات غريبة ، فإن التحقق من الإخراج بكل من ls و readlink ، حيث إن ls readlink مسارات "مبسطة" ، تستبدل ? لأشياء مثل الخطوط الجديدة.

absolute_path=$(readlink -e -- "${BASH_SOURCE[0]}" && echo x) && absolute_path=${absolute_path%?x}
dir=$(dirname -- "$absolute_path" && echo x) && dir=${dir%?x}
file=$(basename -- "$absolute_path" && echo x) && file=${file%?x}

ls -l -- "$dir/$file"
printf '$absolute_path: "%s"\n' "$absolute_path"

للأنظمة التي تحتوي على GNU coreutils readlink (على سبيل المثال. linux):

$(readlink -f "$(dirname "$0")")

لا يلزم استخدام BASH_SOURCE عندما يحتوي $0 على اسم ملف البرنامج النصي.


هذا يحصل على دليل العمل الحالي على نظام التشغيل Mac OS X 10.6.6:

DIR=$(cd "$(dirname "$0")"; pwd)

هذه هي الطريقة البسيطة والصحيحة:

actual_path=$(readlink -f "${BASH_SOURCE[0]}")
script_dir=$(dirname "$actual_path")

تفسير:

  • ${BASH_SOURCE[0]} - المسار الكامل للبرنامج النصي. ستكون قيمة هذا الأمر صحيحة حتى عندما يكون مصدر البرنامج النصي ، على سبيل المثال source <(echo 'echo $0') يطبع bash ، بينما ${BASH_SOURCE[0]} استبداله بـ ${BASH_SOURCE[0]} إلى طباعة المسار الكامل للبرنامج النصي. (بالطبع ، هذا يفترض أنك موافق اتخاذ تبعية على باش.)

  • readlink -f - يقوم بشكل متكرر بحل أي readlink -f في المسار المحدد. هذا هو ملحق GNU ، وغير متوفر على (على سبيل المثال) أنظمة BSD. إذا كنت تقوم بتشغيل Mac ، فيمكنك استخدام Homebrew لتركيب coreutils GNU coreutils محل ذلك باستخدام greadlink -f .

  • وبالطبع يحصل على dirname الرئيسي للمسار.


وأشار تنقيح طفيف للحل ساتيس الإلكترونية و 3 bcdnlklvc04a في جوابهم

SCRIPT_DIR=''
pushd "$(dirname "$(readlink -f "$BASH_SOURCE")")" > /dev/null && {
    SCRIPT_DIR="$PWD"
    popd > /dev/null
}    

يجب أن يعمل هذا في جميع الحالات التي تم إدراجها فيها.

تحرير: منع popd بعد فشل pushd ، وذلك بفضل konsolebox


يجب أن يفعل ذلك:

DIR=$(dirname "$(readlink -f "$0")")

يعمل مع symlinks والمسافات في المسار. انظر صفحات رجل ل dirname و readlink .

تصحيح:

يبدو أنه لا يعمل مع Mac OS من مسار التعليق. ليس لدي فكرة لماذا هذا هو. أي اقتراحات؟


يمكنك استخدام $ BASH_SOURCE

#!/bin/bash

scriptdir=`dirname "$BASH_SOURCE"`

لاحظ أنك تحتاج إلى استخدام #! / bin / bash وليس #! / bin / sh نظرًا لأنه ملحق bash


$_ يستحق الذكر كبديل لـ $ 0. إذا كنت تقوم بتشغيل برنامج نصي من bash ، فيمكن تقصير الإجابة المقبولة إلى:

DIR="$( dirname "$_" )"

لاحظ أن هذا يجب أن يكون العبارة الأولى في البرنامج النصي الخاص بك.


جرب استخدام:

real=$(realpath $(dirname $0))

جرّب الحل المتقاطع التالي المتوافق:

CWD="$(cd -P -- "$(dirname -- "$0")" && pwd -P)"

كما realpathأو readlinkالأوامر ليست متاحة دائما (اعتمادا على نظام التشغيل)، و ${BASH_SOURCE[0]}يتوفر فقط في قذيفة باش.

بدلاً من ذلك ، يمكنك تجربة الوظيفة التالية في bash:

realpath () {
  [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"
}

تأخذ هذه الوظيفة وسيطة واحدة. إذا كان لدى الوسيطة مسار مطلق بالفعل ، فقم بطباعته كما هو ، وإلا قم بطباعة $PWDوسيطة المتغير + اسم الملف (بدون ./البادئة).

ذات صلة:


هذه هي الطريقة الوحيدة التي وجدتها لأقولها بشكل موثوق:

SCRIPT_DIR=$(dirname $(cd "$(dirname "$BASH_SOURCE")"; pwd))

يعمل هذا في bash-3.2:

path="$( dirname "$( which "$0" )" )"

إليك مثال على استخدامه:

لنفترض أن لديك دليل ~ / bin ، في PATH $ . لديك البرنامج النصي A داخل هذا الدليل. انها مصدر البرنامج النصي ~ / بن / ليب / ب . أنت تعرف أين يكون النص المتضمن مرتبطًا بالنص الأصلي ( lib subdirectory lib ) ، ولكن ليس مكانه بالنسبة إلى الدليل الحالي للمستخدم.

يتم حل هذا عن طريق ما يلي (داخل A ):

source "$( dirname "$( which "$0" )" )/lib/B"

لا يهم مكان المستخدم أو الطريقة التي يستدعي بها النص البرمجي ، فسيعمل هذا دائمًا.


لذا ... أعتقد أنني حصلت على هذا. في وقت متأخر للحزب ، ولكن أعتقد أن البعض سيقدر أنه يجري هنا هو أنها تأتي عبر هذا الموضوع. يجب أن توضح التعليقات.

#!/bin/sh # dash bash ksh # !zsh (issues). G. Nixon, 12/2013. Public domain.

## 'linkread' or 'fullpath' or (you choose) is a little tool to recursively
## dereference symbolic links (ala 'readlink') until the originating file
## is found. This is effectively the same function provided in stdlib.h as
## 'realpath' and on the command line in GNU 'readlink -f'.

## Neither of these tools, however, are particularly accessible on the many
## systems that do not have the GNU implementation of readlink, nor ship
## with a system compiler (not to mention the requisite knowledge of C).

## This script is written with portability and (to the extent possible, speed)
## in mind, hence the use of printf for echo and case statements where they
## can be substituded for test, though I've had to scale back a bit on that.

## It is (to the best of my knowledge) written in standard POSIX shell, and
## has been tested with bash-as-bin-sh, dash, and ksh93. zsh seems to have
## issues with it, though I'm not sure why; so probably best to avoid for now.

## Particularly useful (in fact, the reason I wrote this) is the fact that
## it can be used within a shell script to find the path of the script itself.
## (I am sure the shell knows this already; but most likely for the sake of
## security it is not made readily available. The implementation of "$0"
## specificies that the $0 must be the location of **last** symbolic link in
## a chain, or wherever it resides in the path.) This can be used for some
## ...interesting things, like self-duplicating and self-modifiying scripts.

## Currently supported are three errors: whether the file specified exists
## (ala ENOENT), whether its target exists/is accessible; and the special
## case of when a sybolic link references itself "foo -> foo": a common error
## for beginners, since 'ln' does not produce an error if the order of link
## and target are reversed on the command line. (See POSIX signal ELOOP.)

## It would probably be rather simple to write to use this as a basis for
## a pure shell implementation of the 'symlinks' util included with Linux.

## As an aside, the amount of code below **completely** belies the amount
## effort it took to get this right -- but I guess that's coding for you.

##===-------------------------------------------------------------------===##

for argv; do :; done # Last parameter on command line, for options parsing.

## Error messages. Use functions so that we can sub in when the error occurs.

recurses(){ printf "Self-referential:\n\t$argv ->\n\t$argv\n" ;}
dangling(){ printf "Broken symlink:\n\t$argv ->\n\t"$(readlink "$argv")"\n" ;}
errnoent(){ printf "No such file: "[email protected]"\n" ;} # Borrow a horrible signal name.

# Probably best not to install as 'pathfull', if you can avoid it.

pathfull(){ cd "$(dirname "[email protected]")"; link="$(readlink "$(basename "[email protected]")")"

## 'test and 'ls' report different status for bad symlinks, so we use this.

 if [ ! -e "[email protected]" ]; then if $(ls -d "[email protected]" 2>/dev/null) 2>/dev/null;  then
    errnoent 1>&2; exit 1; elif [ ! -e "[email protected]" -a "$link" = "[email protected]" ];   then
    recurses 1>&2; exit 1; elif [ ! -e "[email protected]" ] && [ ! -z "$link" ]; then
    dangling 1>&2; exit 1; fi
 fi

## Not a link, but there might be one in the path, so 'cd' and 'pwd'.

 if [ -z "$link" ]; then if [ "$(dirname "[email protected]" | cut -c1)" = '/' ]; then
   printf "[email protected]\n"; exit 0; else printf "$(pwd)/$(basename "[email protected]")\n"; fi; exit 0
 fi

## Walk the symlinks back to the origin. Calls itself recursivly as needed.

 while [ "$link" ]; do
   cd "$(dirname "$link")"; newlink="$(readlink "$(basename "$link")")"
   case "$newlink" in
    "$link") dangling 1>&2 && exit 1                                       ;;
         '') printf "$(pwd)/$(basename "$link")\n"; exit 0                 ;;
          *) link="$newlink" && pathfull "$link"                           ;;
   esac
 done
 printf "$(pwd)/$(basename "$newlink")\n"
}

## Demo. Install somewhere deep in the filesystem, then symlink somewhere 
## else, symlink again (maybe with a different name) elsewhere, and link
## back into the directory you started in (or something.) The absolute path
## of the script will always be reported in the usage, along with "$0".

if [ -z "$argv" ]; then scriptname="$(pathfull "$0")"

# Yay ANSI l33t codes! Fancy.
 printf "\n\033[3mfrom/as: \033[4m$0\033[0m\n\n\033[1mUSAGE:\033[0m   "
 printf "\033[4m$scriptname\033[24m [ link | file | dir ]\n\n         "
 printf "Recursive readlink for the authoritative file, symlink after "
 printf "symlink.\n\n\n         \033[4m$scriptname\033[24m\n\n        "
 printf " From within an invocation of a script, locate the script's "
 printf "own file\n         (no matter where it has been linked or "
 printf "from where it is being called).\n\n"

else pathfull "[email protected]"
fi

#!/bin/sh
PRG="$0"

# need this for relative symlinks
while [ -h "$PRG" ] ; do
   PRG=`readlink "$PRG"`
done

scriptdir=`dirname "$PRG"`

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"

هو عبارة عن أداة مفيدة واحدة ستعطيك اسم الدليل الكامل للبرنامج النصي بغض النظر عن المكان الذي يتم الاتصال به منه.

ستعمل طالما أن آخر مكون للمسار المستخدم للعثور على البرنامج النصي ليس رابطًا (روابط الدليل هي موافق). إذا كنت تريد أيضًا حل أي روابط للبرنامج النصي نفسه ، فستحتاج إلى حل متعدد الأسطر:

SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
  DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null && pwd )"
  SOURCE="$(readlink "$SOURCE")"
  [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null && pwd )"

سيعمل هذا الأخير مع أي مجموعة من الأسماء المستعارة ، source ، bash -c ، symlinks ، إلخ.

كن حذرًا: إذا قمت cd على دليل مختلف قبل تشغيل هذا المقتطف ، فقد تكون النتيجة غير صحيحة! أيضًا ، احترس من $CDPATH gotchas .

لفهم كيفية عمله ، حاول تشغيل هذا النموذج الأكثر إلمامًا:

#!/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'"

وستقوم بطباعة شيء مثل:

SOURCE './scriptdir.sh' is a relative symlink to 'sym2/scriptdir.sh' (relative to '.')
SOURCE is './sym2/scriptdir.sh'
DIR './sym2' resolves to '/home/ubuntu/dotfiles/fo fo/real/real1/real2'
DIR is '/home/ubuntu/dotfiles/fo fo/real/real1/real2'

SCRIPT_DIR=$( cd ${0%/*} && pwd -P )




directory