Cách lấy thư mục nguồn của tập lệnh Bash từ trong chính tập lệnh


4950

Làm thế nào để tôi có được đường dẫn của thư mục chứa tập lệnh Bash , bên trong tập lệnh đó?

Tôi muốn sử dụng tập lệnh Bash làm trình khởi chạy cho một ứng dụng khác. Tôi muốn thay đổi thư mục làm việc thành thư mục chứa tập lệnh Bash, vì vậy tôi có thể thao tác trên các tệp trong thư mục đó, như vậy:

$ ./application

69
Không có giải pháp hiện tại nào hoạt động nếu có bất kỳ dòng mới nào ở cuối tên thư mục - Chúng sẽ bị loại bỏ bởi sự thay thế lệnh. Để giải quyết vấn đề này, bạn có thể nối thêm một ký tự không phải dòng mới bên trong thay thế lệnh - DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd && echo x)"- và loại bỏ nó mà không cần thay thế lệnh - DIR="${DIR%x}".
l0b0

80
@ jpmc26 Có hai tình huống rất phổ biến: Tai nạn và phá hoại. Một kịch bản không nên thất bại theo những cách không thể đoán trước chỉ vì ai đó, ở đâu đó, đã làm a mkdir $'\n'.
l0b0

24
bất cứ ai cho phép mọi người phá hoại hệ thống của họ theo cách đó không nên bỏ qua nó để phát hiện ra những vấn đề như vậy ... ít thuê những người có khả năng phạm phải sai lầm đó. Tôi chưa bao giờ có, trong 25 năm sử dụng bash, đã thấy loại điều này xảy ra ở bất cứ đâu .... đây là lý do tại sao chúng ta có những thứ như perl và thực hành như kiểm tra mờ nhạt (tôi có thể sẽ bị kích động khi nói rằng :)
osirisgothra

3
@ l0b0 Hãy xem xét rằng bạn cần có sự bảo vệ tương tự dirnamevà thư mục có thể bắt đầu bằng -(ví dụ --help). DIR=$(reldir=$(dirname -- "$0"; echo x); reldir=${reldir%?x}; cd -- "$reldir" && pwd && echo x); DIR=${DIR%?x}. Có lẽ đây là quá mức cần thiết?
Điểm_Under

56
Tôi kiên quyết đề nghị đọc Câu hỏi thường gặp về Bash này về chủ đề này.
Rany Albeg Wein

Câu trả lời:


6571
#!/bin/bash

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

là một lớp lót hữu ích sẽ cung cấp cho bạn tên thư mục đầy đủ của tập lệnh bất kể nó được gọi từ đâu.

Nó sẽ hoạt động miễn là thành phần cuối cùng của đường dẫn được sử dụng để tìm tập lệnh không phải là một liên kết tượng trưng (liên kết thư mục là OK). Nếu bạn cũng muốn tự giải quyết bất kỳ liên kết nào đến tập lệnh, bạn cần một giải pháp đa dòng:

#!/bin/bash

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 2>&1 && 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 2>&1 && pwd )"

Người cuối cùng này sẽ làm việc với bất kỳ sự kết hợp của các bí danh, source, bash -c, liên kết tượng trưng vv

Chú ý: nếu bạn cdđến một thư mục khác trước khi chạy đoạn mã này, kết quả có thể không chính xác!

Ngoài ra, hãy coi chừng $CDPATHgotchas và tác dụng phụ của đầu ra stderr nếu người dùng đã ghi đè cd một cách thông minh để chuyển hướng đầu ra sang stderr thay vào đó (bao gồm các chuỗi thoát, chẳng hạn như khi gọi update_terminal_cwd >&2trên Mac). Thêm >/dev/null 2>&1vào cuối cdlệnh của bạn sẽ chăm sóc cả hai khả năng.

Để hiểu cách thức hoạt động của nó, hãy thử chạy hình thức dài dòng hơn này:

#!/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" )" >/dev/null 2>&1 && pwd )"
if [ "$DIR" != "$RDIR" ]; then
  echo "DIR '$RDIR' resolves to '$DIR'"
fi
echo "DIR is '$DIR'"

Và nó sẽ in một cái gì đó như:

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'

27
Bạn có thể hợp nhất cách tiếp cận này với câu trả lời của user25866 để đi đến một giải pháp phù hợp với source <script>bash <script>: DIR="$(cd -P "$(dirname "${BASH_SOURCE[0]}")" && pwd)".
Dan Mould

21
Đôi khi cdin một cái gì đó để STDOUT! Ví dụ, nếu bạn $CDPATH.. Để giải quyết trường hợp này, hãy sử dụngDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" > /dev/null && pwd )"
user716468

182
Câu trả lời được chấp nhận này là không ổn, nó không hoạt động với các liên kết tượng trưng và quá phức tạp. dirname $(readlink -f $0)là mệnh lệnh đúng. Xem gist.github.com/tvlooy/cbfbdb111a4ebad8b93e để biết thử nghiệm
tvlooy

167
@tvlooy IMO câu trả lời của bạn không chính xác như vậy, vì nó thất bại khi có một khoảng trống trên đường dẫn. Trái ngược với một nhân vật mới, điều này không có khả năng hoặc thậm chí không phổ biến. dirname "$(readlink -f "$0")"không thêm phức tạp và là biện pháp công bằng mạnh mẽ hơn cho số lượng rắc rối tối thiểu.
Adrian Günter

10
@tvlooy nhận xét của bạn không tương thích với macOS (hoặc có thể là BSD nói chung), trong khi câu trả lời được chấp nhận là. readlink -f $0cho readlink: illegal option -- f.
Alexander Ljungberg

875

Sử dụng dirname "$0":

#!/bin/bash
echo "The script you are running has basename `basename "$0"`, dirname `dirname "$0"`"
echo "The present working directory is `pwd`"

sử dụng pwdmột mình sẽ không hoạt động nếu bạn không chạy tập lệnh từ thư mục chứa trong đó.

[matt@server1 ~]$ pwd
/home/matt
[matt@server1 ~]$ ./test2.sh
The script you are running has basename test2.sh, dirname .
The present working directory is /home/matt
[matt@server1 ~]$ cd /tmp
[matt@server1 tmp]$ ~/test2.sh
The script you are running has basename test2.sh, dirname /home/matt
The present working directory is /tmp

25
Đối với tính di động ngoài bash, $ 0 có thể không phải lúc nào cũng đủ. Bạn có thể cần phải thay thế "gõ -p $ 0" để thực hiện công việc này nếu lệnh được tìm thấy trên đường dẫn.
Darron

10
@Darron: bạn chỉ có thể sử dụng type -pnếu tập lệnh có thể thực thi được. Điều này cũng có thể mở một lỗ hổng tinh tế nếu tập lệnh được thực thi bằng cách sử dụng bash test2.shvà có một tập lệnh khác có cùng tên được thực thi ở một nơi khác.
D.Shawley

90
@Darron: nhưng vì câu hỏi được gắn thẻ bashvà dòng hash-bang đề cập rõ ràng /bin/bashnên tôi nói rằng nó khá an toàn khi phụ thuộc vào bashism.
Joachim Sauer

34
+1, nhưng vấn đề với việc sử dụng dirname $0là nếu thư mục là thư mục hiện tại, bạn sẽ nhận được .. Điều đó tốt trừ khi bạn sẽ thay đổi thư mục trong tập lệnh và mong muốn sử dụng đường dẫn bạn nhận được dirname $0như thể nó là tuyệt đối. Để có được đường dẫn tuyệt đối: pushd `dirname $0` > /dev/null, SCRIPTPATH=`pwd`, popd > /dev/null: pastie.org/1489386 (Nhưng chắc chắn có một cách tốt hơn để mở rộng con đường mà?)
TJ Crowder

9
@TJ Crowder Tôi không chắc chắn dirname $0có vấn đề gì không nếu bạn gán nó cho một biến và sau đó sử dụng nó để khởi chạy một tập lệnh như $dir/script.sh; Tôi sẽ tưởng tượng đây là trường hợp sử dụng cho loại điều này 90% thời gian. ./script.shsẽ làm việc tốt
matt b

515

Các dirnamelệnh cơ bản, chỉ cần phân tích các con đường lên đến tên tập tin giảm giá của hầu hết $0(tên script) biến:

dirname "$0"

Nhưng, như matt b đã chỉ ra, đường dẫn được trả về là khác nhau tùy thuộc vào cách gọi tập lệnh. pwdkhông thực hiện công việc vì nó chỉ cho bạn biết thư mục hiện tại là gì chứ không phải thư mục nằm trong thư mục nào. Ngoài ra, nếu một liên kết tượng trưng đến tập lệnh được thực thi, bạn sẽ có đường dẫn (có thể là tương đối) đến nơi liên kết cư trú, không phải là kịch bản thực tế.

Một số người khác đã đề cập đến readlinklệnh, nhưng đơn giản nhất, bạn có thể sử dụng:

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

readlinksẽ giải quyết đường dẫn tập lệnh đến một đường dẫn tuyệt đối từ thư mục gốc của hệ thống tập tin. Vì vậy, bất kỳ đường dẫn nào chứa các dấu chấm đơn hoặc kép, dấu ngã và / hoặc liên kết tượng trưng sẽ được giải quyết thành một đường dẫn đầy đủ.

Đây là một kịch bản thể hiện từng điều này , 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))"

Chạy tập lệnh này trong thư mục nhà của tôi, sử dụng đường dẫn tương đối:

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

Một lần nữa, nhưng sử dụng đường dẫn đầy đủ đến tập lệnh:

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

Bây giờ thay đổi thư mục:

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

Và cuối cùng sử dụng một liên kết tượng trưng để thực thi tập lệnh:

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

13
readlinksẽ không có sẵn trong một số nền tảng trong cài đặt mặc định. Cố gắng tránh sử dụng nó nếu bạn có thể
TL

43
hãy cẩn thận để trích dẫn mọi thứ để tránh các vấn đề về khoảng trắng:export SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
Catskul

13
Trong OSX Yosemite 10.10.1 -fkhông được công nhận là một tùy chọn readlink. Sử dụng stat -fthay vì làm công việc. Cảm ơn
cucu8

11
Trong OSX, greadlinkvề cơ bản, readlinktất cả chúng ta đều quen thuộc. Đây là một phiên bản độc lập với nền tảng:dir=`greadlink -f ${BASH_SOURCE[0]} || readlink -f ${BASH_SOURCE[0]}`
robert

6
Cuộc gọi tốt, @robert. FYI, greadlinkcó thể dễ dàng cài đặt thông qua homebrew:brew install coreutils
phatblat

184
pushd . > /dev/null
SCRIPT_PATH="${BASH_SOURCE[0]}"
if ([ -h "${SCRIPT_PATH}" ]); then
  while([ -h "${SCRIPT_PATH}" ]); do cd `dirname "$SCRIPT_PATH"`; 
  SCRIPT_PATH=`readlink "${SCRIPT_PATH}"`; done
fi
cd `dirname ${SCRIPT_PATH}` > /dev/null
SCRIPT_PATH=`pwd`;
popd  > /dev/null

Hoạt động cho tất cả các phiên bản, bao gồm

  • khi được gọi thông qua liên kết mềm đa chiều sâu,
  • khi tập tin
  • khi script được gọi bởi toán tử " source" aka .(dot).
  • khi arg $0được sửa đổi từ người gọi.
  • "./script"
  • "/full/path/to/script"
  • "/some/path/../../another/path/script"
  • "./some/folder/script"

Ngoài ra, nếu chính tập lệnh bash là một liên kết tượng trưng tương đối mà bạn muốn theo dõi nó và trả về đường dẫn đầy đủ của tập lệnh được liên kết đến:

pushd . > /dev/null
SCRIPT_PATH="${BASH_SOURCE[0]}";
if ([ -h "${SCRIPT_PATH}" ]) then
  while([ -h "${SCRIPT_PATH}" ]) do cd `dirname "$SCRIPT_PATH"`; SCRIPT_PATH=`readlink "${SCRIPT_PATH}"`; done
fi
cd `dirname ${SCRIPT_PATH}` > /dev/null
SCRIPT_PATH=`pwd`;
popd  > /dev/null

SCRIPT_PATHđược đưa ra trong đường dẫn đầy đủ, bất kể nó được gọi như thế nào.
Chỉ cần chắc chắn rằng bạn xác định vị trí này khi bắt đầu kịch bản.

Nhận xét và mã Copyleft này, giấy phép có thể lựa chọn theo GPL2.0 trở lên hoặc CC-SA 3.0 (CreativeCommons Share Alike) trở lên. (c) 2008 Tất cả các quyền. Không bảo hành dưới bất kỳ hình thức nào. Bạn đã được cảnh báo.
http://www.gnu.org/licenses/gpl-2.0.txt
http://creativecommons.org/licenses/by-sa/3.0/
18eedfe1c99df68dc94d4a94712a71aaa8e1e9e36cacf421b9463dd2bbaa02906dd


4
Đẹp! Có thể được thực hiện ngắn hơn thay thế "pushd [...] popd / dev / null" bằng SCRIPT_PATH = readlink -f $(dirname "${VIRTUAL_ENV}");
e-satis

5
Và thay vì sử dụng Pushd ...; sẽ không tốt hơn nếu sử dụng $ (cd dirname "${SCRIPT_PATH}"&& pwd)? Nhưng dù sao kịch bản tuyệt vời!
ovanes

6
Thật nguy hiểm khi tập lệnh cdra khỏi thư mục hiện tại với hy vọng sẽ cdquay lại sau: Tập lệnh có thể không được phép thay đổi thư mục trở lại thư mục hiện tại khi nó được gọi. (Tương tự với Pushd / popd)
Adrian Pronk

7
readlink -flà đặc trưng của GNU. BSD readlinkkhông có tùy chọn đó.
Kara Brightwell

3
Những gì với tất cả các subshells không cần thiết? ([ ... ])kém hiệu quả hơn [ ... ]và không có lợi thế nào cho sự cô lập được đưa ra để đổi lấy hiệu suất đạt được ở đây.
Charles Duffy

110

Câu trả lời ngắn:

`dirname $0`

hoặc ( tốt nhất là ):

$(dirname "$0")

17
Nó sẽ không hoạt động nếu bạn nguồn kịch bản. "nguồn my / script.sh"
Arunprasad Rajkumar

Tôi sử dụng tất cả thời gian trong các tập lệnh bash của mình để tự động hóa công cụ và thường gọi các tập lệnh khác trong cùng một thư mục. Tôi không bao giờ sử dụng sourcetrên những thứ này và cd $(dirname $0)rất dễ nhớ.
kqw

16
@vidstige: ${BASH_SOURCE[0]}thay vì $0sẽ làm việc vớisource my/script.sh
Timothy Jones

@TimothyJones sẽ thất bại 100% nếu lấy từ bất kỳ vỏ nào khác ngoài bash. ${BASH_SOURCE[0]}không thỏa đáng chút nào ${BASH_SOURCE:-0}tốt hơn nhiều
Mathieu CAROFF

106

Bạn có thể sử dụng $BASH_SOURCE:

#!/bin/bash

scriptdir=`dirname "$BASH_SOURCE"`

Lưu ý rằng bạn cần sử dụng #!/bin/bashvà không phải #!/bin/shlà phần mở rộng Bash.


14
Khi tôi làm ./foo/script, sau đó $(dirname $BASH_SOURCE)./foo.
Đến

1
@Till, Trong trường hợp này, chúng ta có thể sử dụng realpathlệnh để có được đường dẫn đầy đủ của ./foo/script. Vì vậy, dirname $(realpath ./foo/script) sẽ đưa ra con đường của kịch bản.
purushothaman poovai

73

Điều này nên làm điều đó:

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

Điều này hoạt động với các liên kết tượng trưng và không gian trong đường dẫn.

Xem các trang người đàn ông cho dirnamereadlink.

Từ theo dõi bình luận có vẻ như không hoạt động với Mac OS. Tôi không biết tại sao lại như vậy. Bất kỳ đề xuất?


6
với giải pháp của bạn, gọi tập lệnh như ./script.shchương trình .thay vì đường dẫn thư mục đầy đủ
Bruno Negrão Zica

5
Không có tùy chọn -f cho đường dẫn đọc trên MacOS. Sử dụng statthay thế. Tuy nhiên, nó vẫn hiển thị .nếu bạn đang ở trong 'thư mục' này.
Denis The Menace

2
Bạn cần cài đặt coreutilstừ Homebrew và sử dụng greadlinkđể có -ftùy chọn trên MacOS vì đó là * BSD dưới vỏ bọc chứ không phải Linux.
dragon788

Bạn nên thêm dấu ngoặc kép xung quanh tất cả phía bên tay phải:DIR="$(dirname "$(readlink -f "$0")")"
hagello

60

pwdcó thể được sử dụng để tìm thư mục làm việc hiện tại và dirnameđể tìm thư mục của một tệp cụ thể (lệnh đã được chạy $0, vì vậy dirname $0sẽ cung cấp cho bạn thư mục của tập lệnh hiện tại).

Tuy nhiên, dirnameđưa ra chính xác phần thư mục của tên tệp, nhiều khả năng sẽ không liên quan đến thư mục làm việc hiện tại. Nếu kịch bản của bạn cần thay đổi thư mục vì một số lý do, thì đầu ra từ dirnametrở nên vô nghĩa.

Tôi đề nghị như sau:

#!/bin/bash

reldir=`dirname $0`
cd $reldir
directory=`pwd`

echo "Directory is $directory"

Bằng cách này, bạn có được một thư mục tuyệt đối, thay vì tương đối.

Vì tập lệnh sẽ được chạy trong một trường hợp bash riêng, sau đó không cần khôi phục thư mục làm việc, nhưng nếu bạn muốn thay đổi lại tập lệnh của mình vì một số lý do, bạn có thể dễ dàng gán giá trị của pwdmột biến trước khi bạn thay đổi thư mục, để sử dụng trong tương lai.

Mặc dù chỉ

cd `dirname $0`

giải quyết tình huống cụ thể trong câu hỏi, tôi thấy có đường dẫn tuyệt đối để hữu dụng hơn nói chung.


9
Bạn có thể làm tất cả trong một dòng như thế này: TRỰC TIẾP = $ (cd dirname $0&& pwd)
dogbane

Điều này không hoạt động nếu tập lệnh lấy một tập lệnh khác và bạn muốn biết tên của tập lệnh sau.
Revierpost

52

Tôi cảm thấy mệt mỏi khi đến trang này nhiều lần để sao chép dán một lớp trong câu trả lời được chấp nhận. Vấn đề với nó là không dễ hiểu và dễ nhớ.

Đây là một kịch bản dễ nhớ:

DIR="$(dirname "${BASH_SOURCE[0]}")"  # get the directory name
DIR="$(realpath "${DIR}")"    # resolve its full path if need be

2
Hoặc, rõ ràng hơn, trên một dòng: DIR=$(realpath "$(dirname "${BASH_SOURCE[0]}")")
agc

Tại sao đây không phải là câu trả lời được chấp nhận? Có sự khác biệt nào khi sử dụng realpathtừ việc giải quyết "thủ công" với một vòng lặp readlinkkhông? Ngay cả readlinktrang người đàn ông cũng nóiNote realpath(1) is the preferred command to use for canonicalization functionality.
User9123

1
Và nhân tiện chúng ta không nên áp dụng realpathtrước dirname, không phải sau? Nếu chính tập tin script là một symlink ... Nó sẽ cung cấp một cái gì đó như thế DIR="$(dirname "$(realpath "${BASH_SOURCE[0]}")")". Thật ra rất gần với câu trả lời của Simon.
Người dùng9123

@ User9123 Tôi nghĩ rằng chấp nhận một là cố gắng tương thích với tất cả các shell / distro phổ biến. Hơn nữa, tùy thuộc vào những gì bạn đang cố gắng thực hiện, trong hầu hết các trường hợp, mọi người muốn lấy thư mục chứa liên kết tượng trưng thay vì thư mục của nguồn thực tế.
Vương

37

Tôi không nghĩ rằng điều này là dễ dàng như những người khác đã làm được. pwdkhông hoạt động, vì thư mục hiện tại không nhất thiết là thư mục có tập lệnh. $0không phải lúc nào cũng có thông tin. Hãy xem xét ba cách sau để gọi một tập lệnh:

./script

/usr/bin/script

script

Trong cách thứ nhất và thứ ba $0không có thông tin đường dẫn đầy đủ. Trong thứ hai và thứ ba, pwdkhông hoạt động. Cách duy nhất để có được thư mục theo cách thứ ba là chạy qua đường dẫn và tìm tệp có kết quả khớp chính xác. Về cơ bản mã sẽ phải làm lại những gì HĐH làm.

Một cách để làm những gì bạn đang yêu cầu là chỉ mã hóa dữ liệu trong /usr/sharethư mục và tham chiếu nó theo đường dẫn đầy đủ của nó. Dữ liệu sẽ không có trong /usr/binthư mục, vì vậy đây có lẽ là việc cần làm.


9
Nếu bạn có ý định từ chối bình luận của anh ấy, hãy CHẮC CHẮN rằng một tập lệnh CÓ THỂ truy cập vào nơi nó được lưu trữ với một ví dụ mã.
Richard Duerr

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

Đây là cách ngắn hơn so với câu trả lời được chọn. Và xuất hiện để làm việc như là tốt. Điều này xứng đáng 1000 phiếu chỉ để mọi người không bỏ qua nó.
Patrick

2
Như nhiều câu trả lời trước giải thích chi tiết, cả hai đều $0không pwdđược đảm bảo có thông tin chính xác, tùy thuộc vào cách tập lệnh được gọi.
IMSoP

34
$(dirname "$(readlink -f "$BASH_SOURCE")")

Tôi thích $BASH_SOURCEhơn $0, bởi vì nó rõ ràng ngay cả đối với những độc giả không rành về bash. $(dirname -- "$(readlink -f -- "$BASH_SOURCE")")
blobmaster

32

Điều này nhận được thư mục làm việc hiện tại trên Mac OS X 10.6.6:

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

27

Đây là Linux cụ thể, nhưng bạn có thể sử dụng:

SELF=$(readlink /proc/$$/fd/255)

1
Đó cũng là bash cụ thể, nhưng có lẽ hành vi của bash đã thay đổi? /proc/fd/$$/255dường như chỉ đến tty, không phải là một thư mục. Ví dụ: trong trình đăng nhập hiện tại của tôi, các mô tả tệp 0, 1, 2 và 255 đều tham chiếu /dev/pts/4. Trong mọi trường hợp, hướng dẫn sử dụng bash không đề cập đến fd 255, do đó có thể không phụ thuộc vào hành vi này. \
Keith Thompson

2
Vỏ tương tác! = Kịch bản. Dù sao realpath ${BASH_SOURCE[0]};dường như là cách tốt nhất để đi.
Steve Baker

23

Dưới đây là một lớp lót tuân thủ POSIX:

SCRIPT_PATH=`dirname "$0"`; SCRIPT_PATH=`eval "cd \"$SCRIPT_PATH\" && pwd"`

# test
echo $SCRIPT_PATH

4
Tôi đã thành công với điều này khi tự chạy một tập lệnh hoặc bằng cách sử dụng sudo, nhưng không phải khi gọi nguồn ./script.sh
Michael R

Và nó thất bại khi cdđược cấu hình để in tên đường dẫn mới.
Aaron Digulla

18

Tôi đã thử tất cả những thứ này và không cái nào hiệu quả. Một con rất gần nhưng có một con bọ nhỏ đã phá vỡ nó một cách tồi tệ; họ quên bọc đường dẫn trong dấu ngoặc kép.

Ngoài ra, rất nhiều người cho rằng bạn đang chạy tập lệnh từ trình bao để họ quên khi bạn mở tập lệnh mới, nó mặc định là nhà của bạn.

Hãy thử thư mục này cho kích thước:

/var/No one/Thought/About Spaces Being/In a Directory/Name/And Here's your file.text

Điều này làm cho nó đúng bất kể bạn chạy nó ở đâu và như thế nào:

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

Vì vậy, để làm cho nó thực sự hữu ích, đây là cách thay đổi thư mục của tập lệnh đang chạy:

cd "`dirname "$0"`"

4
Không hoạt động nếu tập lệnh được lấy từ tập lệnh khác.
Revierpost

Điều này không hoạt động nếu phần cuối của $ 0 là một liên kết tượng trưng chỉ đến một mục của thư mục khác ( ln -s ../bin64/foo /usr/bin/foo).
hagello

17

Đây là cách đơn giản, chính xác:

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

Giải trình:

  • ${BASH_SOURCE[0]}- đường dẫn đầy đủ đến kịch bản. Giá trị của điều này sẽ chính xác ngay cả khi tập lệnh đang được lấy nguồn, ví dụ như source <(echo 'echo $0')in bash , trong khi thay thế nó ${BASH_SOURCE[0]}sẽ in toàn bộ đường dẫn của tập lệnh. (Tất nhiên, điều này giả định rằng bạn ổn khi phụ thuộc vào Bash.)

  • readlink -f- Giải quyết đệ quy bất kỳ liên kết tượng trưng nào trong đường dẫn đã chỉ định. Đây là một phần mở rộng GNU và không có sẵn trên (ví dụ) các hệ thống BSD. Nếu bạn đang chạy Mac, bạn có thể sử dụng Homebrew để cài đặt GNU coreutilsvà thay thế điều này bằng greadlink -f.

  • Và tất nhiên dirnamecó được thư mục cha của đường dẫn.


1
greadlink -ftiếc là không hoạt động hiệu quả khi sourcesử dụng tập lệnh trên Mac :(
Gabe Kopley

17

Cách ngắn nhất và thanh lịch nhất để làm điều này là:

#!/bin/bash
DIRECTORY=$(cd `dirname $0` && pwd)
echo $DIRECTORY

Điều này sẽ làm việc trên tất cả các nền tảng và siêu sạch.

Thông tin chi tiết có thể được tìm thấy trong "Thư mục bash đó nằm trong thư mục nào? ".


giải pháp sạch tuyệt vời, nhưng điều này sẽ không hoạt động nếu tập tin được liên kết.
kẻ hủy hoại

16

Tôi sẽ sử dụng một cái gì đó như thế này:

# 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

Đây là một trong những thực tế! Làm việc với đơn giản shquá! Vấn đề với các dirname "$0"giải pháp dựa trên đơn giản : Nếu tập lệnh nằm trong $PATHvà được gọi mà không có đường dẫn, chúng sẽ cho kết quả sai.
Notinlist

@Notinlist Không phải vậy. Nếu tập lệnh được tìm thấy thông qua PATH, $0sẽ chứa tên tệp tuyệt đối. Nếu tập lệnh được gọi với tên tệp tương đối hoặc tuyệt đối chứa a /, $0sẽ chứa tập lệnh đó.
Neil Mayhew

Sẽ không làm việc cho một kịch bản có nguồn gốc.
Amit N Nikol

16

Đây là một sửa đổi nhỏ cho giải pháp e-satis và 3bcdnlklvc04a đã chỉ ra trong câu trả lời của họ :

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

Điều này vẫn sẽ làm việc trong tất cả các trường hợp họ liệt kê.

Điều này sẽ ngăn chặn popdsau khi thất bại pushd, nhờ konsolebox.


Điều này hoạt động hoàn hảo để có được tên thư mục "thực", thay vì chỉ tên của một liên kết tượng trưng. Cảm ơn bạn!
Jay Taylor

1
Tốt hơnSCRIPT_DIR=''; pushd "$(dirname "$(readlink -f "$BASH_SOURCE")")" > /dev/null && { SCRIPT_DIR=$PWD; popd > /dev/null; }
konsolebox

@konsolebox, bạn đang cố gắng chống lại điều gì? Tôi nói chung là một fan hâm mộ của các điều kiện logic nội tuyến, nhưng lỗi cụ thể mà bạn đã thấy trong đẩy là gì? Tôi phù hợp hơn là tìm cách xử lý trực tiếp thay vì trả lại một SCRIPT_DIR trống.
Fuwjax

@Fuwjax Thực hành tự nhiên để tránh làm popdtrong trường hợp (ngay cả khi hiếm) khi pushdthất bại. Và trong trường hợp pushdthất bại, bạn nghĩ giá trị của nó là SCRIPT_DIRgì? Hành động có thể khác nhau tùy thuộc vào những gì có vẻ hợp lý hoặc những gì một người dùng có thể thích nhưng chắc chắn, làm popdlà sai.
konsolebox

Tất cả những pushd popdnguy hiểm đó có thể tránh được chỉ bằng cách thả chúng và sử dụng cd+ pwdkèm theo thay thế lệnh. SCRIPT_DIR=$(...)
Amit N Nikol

16

Đối với các hệ thống có lõi GNU readlink(ví dụ: linux):

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

Không cần sử dụng BASH_SOURCEkhi $0chứa tên tệp script.


3
trừ khi kịch bản có nguồn gốc. hoặc 'nguồn' trong trường hợp đó vẫn sẽ là bất kỳ tập lệnh nào có nguồn gốc từ nó, hoặc, nếu từ dòng lệnh, '-bash' (đăng nhập tty) hoặc 'bash' (được gọi qua 'bash -l') hoặc '/ bin / bash '(được gọi là shell không đăng nhập tương tác)
osirisgothra

Tôi đã thêm cặp trích dẫn thứ hai xung quanh dirnamecuộc gọi. Cần thiết nếu đường dẫn thư mục chứa khoảng trắng.
user1338062

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

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

scriptdir=`dirname "$PRG"`

Tôi đã không thử nó trên các hệ thống khác nhau. Nhưng giải pháp này là giải pháp hoạt động ngay lập tức ít nhất trên Ubuntu, đối với tôi!
Natus đã vẽ

$0sẽ không làm việc cho một kịch bản có nguồn gốc
Amit N Nikol

13

$_là giá trị đề cập như là một thay thế cho $0. Nếu bạn đang chạy tập lệnh từ Bash, câu trả lời được chấp nhận có thể được rút ngắn thành:

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

Lưu ý rằng đây phải là tuyên bố đầu tiên trong kịch bản của bạn.


4
Nó phá vỡ nếu bạn sourcehoặc .kịch bản. Trong các tình huống đó, $_sẽ chứa tham số cuối cùng của lệnh cuối cùng bạn đã chạy trước lệnh .. $BASH_SOURCElàm việc mọi lúc
clacke

11

Tôi đã so sánh nhiều câu trả lời được đưa ra và đưa ra một số giải pháp nhỏ gọn hơn. Chúng dường như xử lý tất cả các trường hợp cạnh điên rồ phát sinh từ sự kết hợp yêu thích của bạn:

  • Đường dẫn tuyệt đối hoặc đường dẫn tương đối
  • Tập tin và thư mục liên kết mềm
  • Gọi như script, bash script, bash -c script, source script, hoặc. script
  • Dấu cách, tab, dòng mới, unicode, v.v. trong thư mục và / hoặc tên tệp
  • Tên tệp bắt đầu bằng dấu gạch nối

Nếu bạn đang chạy từ Linux, có vẻ như sử dụng proctay cầm là giải pháp tốt nhất để xác định nguồn được giải quyết hoàn toàn của tập lệnh hiện đang chạy (trong phiên tương tác, liên kết trỏ đến tương ứng /dev/pts/X):

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

Điều này có một chút xấu xí của nó, nhưng sửa chữa là nhỏ gọn và dễ hiểu. Chúng tôi không chỉ sử dụng nguyên thủy bash, nhưng tôi ổn với điều đó vì readlinkđơn giản hóa công việc đáng kể. Việc echo Xthêm Xvào cuối chuỗi biến để bất kỳ khoảng trắng theo sau nào trong tên tệp không bị ăn và thay thế tham số ${VAR%X}ở cuối dòng sẽ bị loại bỏ X. Bởi vì readlinkthêm một dòng mới của riêng nó (thường sẽ được ăn trong thay thế lệnh nếu không phải vì mánh khóe trước đây của chúng tôi), chúng tôi cũng phải loại bỏ điều đó. Điều này được thực hiện dễ dàng nhất bằng cách sử dụng $''lược đồ trích dẫn, cho phép chúng tôi sử dụng các chuỗi thoát như\n để thể hiện các dòng mới (đây cũng là cách bạn có thể dễ dàng tạo các thư mục và tệp được đặt tên sai lệch).

Ở trên sẽ đáp ứng nhu cầu của bạn để định vị tập lệnh hiện đang chạy trên Linux, nhưng nếu bạn không có prochệ thống tệp theo ý của bạn hoặc nếu bạn đang cố gắng xác định đường dẫn được giải quyết hoàn toàn của một số tệp khác, thì có thể bạn sẽ tìm mã dưới đây hữu ích. Nó chỉ là một sửa đổi nhỏ từ lớp lót trên. Nếu bạn đang chơi xung quanh với thư mục / tên tệp lạ, hãy kiểm tra đầu ra bằng cả hai lsreadlinkcó nhiều thông tin, như lssẽ xuất ra các đường dẫn "đơn giản hóa", thay thế ?cho những thứ như dòng mới.

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"

Tôi nhận được /dev/pts/30với bash trên máy tính để bàn Ubuntu 14.10.
Dan Dascalescu

@DanDascalescu Sử dụng một lớp lót? Hoặc đoạn mã đầy đủ ở phía dưới? Và bạn đã cho nó ăn bất kỳ tên đường khó khăn?
billyjmc

Có một dòng cộng với một dòng để echo $resolved, tôi lưu nó như là d, chmod +x d, ./d.
Dan Dascalescu

@DanDascalescu Dòng đầu tiên trong kịch bản của bạn cần phải là#!/bin/bash
billyjmc

10

Hãy thử sử dụng:

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

1
Tất cả những gì tôi muốn biết là, tại sao cách này không tốt? Nó dường như không có xấu và chính xác cho tôi. Bất cứ ai có thể giải thích tại sao nó bị hạ cấp?
Shou Ya

7
realpath không phải là một tiện ích tiêu chuẩn.
Steve Bennett

2
Trên Linux, realpath là một tiện ích tiêu chuẩn (một phần của gói GNU coreutils), nhưng nó không phải là một bash tích hợp (nghĩa là một hàm được cung cấp bởi chính bash). Nếu bạn đang chạy Linux, phương pháp này có thể sẽ làm việc, mặc dù tôi muốn thay thế $0cho ${BASH_SOURCE[0]}nên phương pháp này sẽ làm việc ở bất cứ đâu, kể cả trong một hàm.
Doug Richardson

3
Thứ tự của các hoạt động trong câu trả lời này là sai. Trước tiên bạn cần giải quyết liên kết tượng trưng, sau đó thực hiện dirnamevì phần cuối cùng $0có thể là một liên kết tượng trưng trỏ đến một tệp không nằm trong cùng thư mục với chính liên kết tượng trưng. Giải pháp được mô tả trong câu trả lời này chỉ lấy đường dẫn của thư mục lưu trữ symlink chứ không phải thư mục của mục tiêu. Hơn nữa, giải pháp này là thiếu trích dẫn. Nó sẽ không hoạt động nếu đường dẫn chứa các ký tự đặc biệt.
hagello

3
dir="$(realpath "$(dirname "${BASH_SOURCE[0]}")")"
Kostiantyn Ponomarenko

9

Hãy thử giải pháp tương thích chéo sau đây:

CWD="$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"

như các lệnh như realpathhoặc readlinkcó thể không có sẵn (tùy thuộc vào hệ điều hành).

Lưu ý: Trong Bash, nó khuyến khích sử dụng ${BASH_SOURCE[0]}thay vì $0, nếu không đường có thể phá vỡ khi tìm nguồn cung ứng các file ( source/ .).

Ngoài ra, bạn có thể thử chức năng sau trong bash:

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

Hàm này có 1 đối số. Nếu đối số đã có đường dẫn tuyệt đối, hãy in nó như hiện tại, nếu không thì in $PWDbiến + đối số tên tệp (không có ./tiền tố).

Liên quan:


Hãy giải thích thêm về chức năng realpath.
Chris

1
realpathHàm @Chris mất 1 đối số. Nếu đối số đã có đường dẫn tuyệt đối, hãy in nó như hiện tại, nếu không thì in $PWD+ tên tệp (không có ./tiền tố).
kenorb

Giải pháp tương thích chéo của bạn không hoạt động khi tập lệnh được liên kết.
Jakub Jiruska

9

Tôi tin rằng tôi đã có cái này. Tôi đến bữa tiệc muộn, nhưng tôi nghĩ một số người sẽ đánh giá cao nó ở đây nếu họ bắt gặp chủ đề này. Các ý kiến ​​nên giải thích:

#!/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: "$@"\n" ;} # Borrow a horrible signal name.

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

pathfull(){ cd "$(dirname "$@")"; link="$(readlink "$(basename "$@")")"

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

 if [ ! -e "$@" ]; then if $(ls -d "$@" 2>/dev/null) 2>/dev/null;  then
    errnoent 1>&2; exit 1; elif [ ! -e "$@" -a "$link" = "$@" ];   then
    recurses 1>&2; exit 1; elif [ ! -e "$@" ] && [ ! -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 "$@" | cut -c1)" = '/' ]; then
   printf "$@\n"; exit 0; else printf "$(pwd)/$(basename "$@")\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 "$@"
fi

8

Đây là những cách ngắn để có được thông tin về tập lệnh:

Thư mục và tập tin:

    Script: "/tmp/src dir/test.sh"
    Calling folder: "/tmp/src dir/other"

Sử dụng các lệnh sau:

    echo Script-Dir : `dirname "$(realpath $0)"`
    echo Script-Dir : $( cd ${0%/*} && pwd -P )
    echo Script-Dir : $(dirname "$(readlink -f "$0")")
    echo
    echo Script-Name : `basename "$(realpath $0)"`
    echo Script-Name : `basename $0`
    echo
    echo Script-Dir-Relative : `dirname "$BASH_SOURCE"`
    echo Script-Dir-Relative : `dirname $0`
    echo
    echo Calling-Dir : `pwd`

Và tôi đã nhận được kết quả này:

     Script-Dir : /tmp/src dir
     Script-Dir : /tmp/src dir
     Script-Dir : /tmp/src dir

     Script-Name : test.sh
     Script-Name : test.sh

     Script-Dir-Relative : ..
     Script-Dir-Relative : ..

     Calling-Dir : /tmp/src dir/other

Xem thêm: https://pastebin.com/J8KjxrPF



Tôi nghĩ rằng câu trả lời của tôi là ok bởi vì thật khó để tìm thấy một phiên bản làm việc đơn giản. Tại đây bạn có thể lấy mã bạn thích, ví dụ cd + pwd, dirname + realpath hoặc dirname + readlink. Tôi không chắc chắn rằng tất cả các phần tồn tại trước đây và hầu hết các câu trả lời là phức tạp và quá tải. Tại đây bạn có thể rút ra mã bạn muốn sử dụng. Ít nhất xin vui lòng không xóa nó khi tôi cần trong tương lai: D
User8461

8

Điều này hoạt động trong bash-3.2:

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

Nếu bạn có một ~/binthư mục trong bạn $PATH, bạn có Atrong thư mục này. Nó nguồn kịch bản ~/bin/lib/B. Bạn biết nơi tập lệnh được bao gồm có liên quan đến tập lệnh gốc, trong libthư mục con, nhưng không phải nơi tập lệnh liên quan đến thư mục hiện tại của người dùng.

Điều này được giải quyết bằng cách sau (bên trong A):

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

Không quan trọng người dùng đang ở đâu hoặc anh ta gọi kịch bản như thế nào, điều này sẽ luôn hoạt động.


3
Điểm trên whichlà rất tranh cãi. type, hashvà các nội trang khác làm điều tương tự tốt hơn trong bash. whichlà loại dễ di chuyển hơn, mặc dù nó thực sự không whichđược sử dụng trong các shell khác như tcsh, nó có dạng dựng sẵn.
Phục hồi Monica Vui lòng

"Luôn luôn"? Không có gì. whichlà một công cụ bên ngoài, bạn không có lý do gì để tin rằng nó hoạt động giống hệt vỏ mẹ.
Charles Duffy

7

Giải pháp nhỏ gọn tốt nhất theo quan điểm của tôi sẽ là:

"$( cd "$( echo "${BASH_SOURCE[0]%/*}" )"; pwd )"

Không có sự phụ thuộc vào bất cứ điều gì khác ngoài Bash. Việc sử dụng dirname, readlinkbasenamecuối cùng sẽ dẫn đến các vấn đề tương thích, do đó, họ tốt nhất nên tránh nếu có thể.


2
Bạn có lẽ nên thêm dấu gạch chéo vào đó : "$( cd "$( echo "${BASH_SOURCE[0]%/*}/" )"; pwd )". Bạn sẽ gặp vấn đề với thư mục gốc nếu không. Ngoài ra tại sao bạn thậm chí phải sử dụng tiếng vang?
konsolebox

dirnamebasenamePOSIX đã được chuẩn hóa, vậy tại sao tránh sử dụng chúng? Liên kết : dirname,basename
myrdd

Ngăn chặn hai dĩa quá trình bổ sung và dính vào vỏ tích hợp có thể là một lý do tại sao.
Amit N Nikol
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.