Xóa thư mục khỏi PATH


28

Tôi đang cố gắng biên dịch wxWidgets bằng MingW và tôi có cygwin trên đường đi của mình, điều này dường như mâu thuẫn. Vì vậy, tôi muốn loại bỏ /d/Programme/cygwin/binkhỏi biến PATH và tôi tự hỏi liệu có cách nào thanh lịch để làm điều này không.

Cách tiếp cận ngây thơ sẽ là lặp lại nó vào một tập tin, xóa nó bằng tay và lấy nguồn, nhưng tôi cá là có cách tiếp cận tốt hơn cho việc này.


2
Nhiều kỹ thuật được liệt kê ở đây: stackoverflow.com/questions/370047/ từ
slm

Câu trả lời:


23

Không có công cụ tiêu chuẩn nào để "chỉnh sửa" giá trị của $ PATH (tức là "chỉ thêm thư mục khi nó chưa tồn tại" hoặc "xóa thư mục này"). Bạn chỉ cần thực hiện:

export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

đó sẽ là phiên hiện tại, nếu bạn muốn thay đổi vĩnh viễn, hãy thêm nó vào bất kỳ .bashrc, bash.bashrc, / etc / profile - bất cứ điều gì phù hợp với nhu cầu của hệ thống và người dùng của bạn. Tuy nhiên, nếu bạn đang sử dụng BASH, bạn cũng có thể thực hiện các thao tác sau nếu giả sử bạn muốn xóa thư mục /home/wrong/dir/khỏi biến PATH của mình, giả sử ở cuối:

PATH=$(echo "$PATH" | sed -e 's/:\/home\/wrong\/dir$//')

Vì vậy, trong trường hợp của bạn, bạn có thể sử dụng

PATH=$(echo "$PATH" | sed -e 's/:\/d\/Programme\/cygwin\/bin$//')

1
Nếu đường dẫn trong câu hỏi nằm ở đầu biến PATH, bạn cần khớp dấu hai chấm ở cuối. Đây là một cảnh báo khó chịu làm phức tạp các thao tác chung dễ dàng của các biến PATH.
Graeme

4
Khi xử lý quá nhiều dấu gạch chéo, tôi thích thay đổi dấu phân cách regex /bằng một cái gì đó như |: PATH=$(echo "$PATH" | sed -e 's|:/d/Programme/cygwin/bin$||')để ngăn chặn tất cả thoát.
Matthias Kuhn

17

Trong bash:

directory_to_remove=/d/Programme/cygwin/bin
PATH=:$PATH:
PATH=${PATH//:$directory_to_remove:/:}
PATH=${PATH#:}; PATH=${PATH%:}

Nếu bạn không sử dụng biến trung gian, bạn cần bảo vệ các /ký tự trong thư mục để xóa để chúng không được coi là phần cuối của văn bản tìm kiếm.

PATH=:$PATH:
PATH=${PATH//:\/d\/Programme\/cygwin\/bin:/:}
PATH=${PATH#:}; PATH=${PATH%:}

Dòng đầu tiên và thứ ba có mặt để sắp xếp cho mọi thành phần của đường dẫn tìm kiếm được bao quanh :, để tránh vỏ đặc biệt thành phần đầu tiên và cuối cùng. Dòng thứ hai loại bỏ thành phần được chỉ định.


Cảm ơn @Gilles, câu trả lời của bạn đã thôi thúc tôi đưa ra giải pháp của riêng mình , việc này chỉ yêu cầu ba thao tác của PATH chứ không phải bốn. * 8 ')
Đánh dấu gian hàng

8

Sau khi xem xét các tùy chọn khác được trình bày ở đây và không hiểu đầy đủ về cách thức một số trong số chúng hoạt động, tôi đã phát triển path_removechức năng của riêng mình , mà tôi đã thêm vào .bashrc:

function path_remove {
  # Delete path by parts so we can never accidentally remove sub paths
  PATH=${PATH//":$1:"/":"} # delete any instances in the middle
  PATH=${PATH/#"$1:"/} # delete any instance at the beginning
  PATH=${PATH/%":$1"/} # delete any instance in the at the end
}

Điều này đã kết thúc khá gần với giải pháp của Gilles nhưng được gói gọn như một hàm bash có thể dễ dàng sử dụng trên dòng lệnh.

Nó có những ưu điểm là với chức năng bash, nó hoạt động như một chương trình mà không cần phải là chương trình trên đường dẫn và nó không yêu cầu bất kỳ chương trình bên ngoài nào để chạy, chỉ cần thao tác chuỗi bash.

Nó xuất hiện khá mạnh mẽ, đặc biệt là nó không biến somepath:mypath/mysubpaththành somepath/mysubpath: nếu bạn chạy path_remove mypath, đó là vấn đề tôi gặp phải với path_removechức năng trước đây .

Một lời giải thích tuyệt vời về cách thao tác chuỗi bash có thể được tìm thấy tại Hướng dẫn Bash-Scripting nâng cao .


6

Vì vậy, kết hợp các câu trả lời từ @gilles và @ bruno-a (và một vài thủ thuật quyến rũ khác) tôi đã đưa ra cách sử dụng một lớp lót này, nó sẽ loại bỏ (mọi) REMISE_PART khỏi PATH, bất kể nó có xảy ra lúc đầu không, giữa hoặc cuối của PATH

PATH=$(REMOVE_PART="/d/Programme/cygwin/bin" sh -c 'echo ":$PATH:" | sed "s@:$REMOVE_PART:@:@g;s@^:\(.*\):\$@\1@"')

Hơi khó sử dụng một chút, nhưng thật tuyệt khi có thể làm điều đó trong một cú đánh. Các ;được sử dụng để tham gia cùng hai lệnh sed riêng biệt:

  • s@:$REMOVE_PART:@:@g(thay thế :$REMOVE_PART:bằng một :)
  • s@^:\(.*\):\$@\1@ (loại bỏ các dấu hai chấm hàng đầu và dấu mà chúng ta đã thêm bằng lệnh echo)

Và dọc theo các dòng tương tự, tôi vừa mới tìm ra được một lớp lót này để thêm ADD_PART vào PATH, chỉ khi PATH không chứa nó

PATH=$(ADD_PART="/d/Programme/cygwin/bin" sh -c 'if echo ":$PATH:" | grep -q ":$ADD_PART:"; then echo "$PATH"; else echo "$ADD_PART:$PATH"; fi')

Thay đổi phần cuối cùng thành echo "$PATH:$ADD_PART"nếu bạn muốn thêm ADD_PART vào cuối PATH thay vì bắt đầu.

...

... Hoặc để làm cho điều này thậm chí dễ dàng hơn, hãy tạo một tập lệnh được gọi remove_path_partvới nội dung

echo ":$PATH:" | sed "s@:$1:@:@g;s@^:\(.*\):\$@\1@"

và một kịch bản được gọi prepend_path_partvới nội dung

if echo ":$PATH:" | grep -q ":$1:"; then echo "$PATH"; else echo "$1:$PATH"; fi

và một kịch bản được gọi append_path_partvới nội dung

if echo ":$PATH:" | grep -q ":$1:"; then echo "$PATH"; else echo "$PATH:$1"; fi

làm cho tất cả chúng có thể thực thi được, và sau đó gọi chúng như:

  • PATH=$(remove_path_part /d/Programme/cygwin/bin)
  • PATH=$(prepend_path_part /d/Programme/cygwin/bin)
  • PATH=$(append_path_part /d/Programme/cygwin/bin)

Gọn gàng, ngay cả khi tôi tự nói như vậy :-)


Tôi thích đề xuất, đặc biệt là ý tưởng với các kịch bản.
Devolus

3

Đơn giản hơn nhiều một lót.

xuất PATH = `echo $ PATH | tr ":" "\ n" | grep -v "anaconda" | tr "\ n" ":" `


2

Đây là một bài tập thú vị để viết một hàm bash để xóa một thư mục khỏi một biến đường dẫn.

Dưới đây là một số chức năng tôi sử dụng trong các tệp .bash * của mình để chắp thêm / thêm các thư mục vào đường dẫn. Họ có ưu điểm là loại bỏ các mục trùng lặp, nếu có, và làm việc với bất kỳ loại biến đường dẫn phân tách ruột kết nào (PATH, MANPATH, INFOPATH, ...). hàm remove_from xóa thư mục.

# {app,pre}pend_to path-var-name dirpath
# remove_from path-var-name dirpath
#
# Functions to manipulate a path-style variable.  {app,pre}pend_to
# both remove any other instances of dirname before adding it to
# the start or end of the path-var-name variable.
#
# Calling example:
#   append_to PATH "/usr/local/bin"
#
# Uses eval to allow target path varname to be passed in.
function remove_from() {
  # add surrounging colons
  eval tmp_path=":\$${1}:"
  # if dir is already there, remove it
  (echo "${tmp_path}" | grep --silent ":${2}:") &&
    tmp_path=`echo "$tmp_path" | sed "s=:${2}:=:=g"`
  # remove surrounding colons
  tmp_path=`echo "$tmp_path" | sed 's=^:==; s=:$=='`
  eval export $1=\"$tmp_path\"
}
function append_to() {
  remove_from "$1" "$2"  # clean the path contents
  eval export $1=\"\$${1}:$2\"
}
function prepend_to() {
  remove_from "$1" "$2"  # clean the path contents
  eval export $1=\"${2}:\$$1\"
}

2

Dưới đây là mã sửa đổi từ giải pháp của Greg Tarsa. Chỉ các lệnh tích hợp bash được sử dụng ở đây. Vì vậy, nó sẽ tiết kiệm rất nhiều cuộc gọi hệ thống fork ().

# Calling example:
#   append_to PATH "/usr/local/bin"

function remove_from()
{
    local path="${1}"
    local dir="${2}"
    local -a dirs=()
    local old_ifs="${IFS}"
    IFS=":"
    set -- ${!path}
    while [ "$#" -gt "0" ]
    do
        [ "${1}" != "${dir}" ] && dirs+=("${1}")
        shift
        done
    eval "export ${path}=\"${dirs[*]}\""
    IFS="${old_ifs}"
}

function append_to()
{
    remove_from "${1}" "${2}"
    [ -d "${2}" ] || return
    if [ -n "${!1}" ]
    then
        eval "export ${1}=\"${!1}:${2}\""
    else
        eval "export ${1}=\"${2}\""
    fi
}

function prepend_to()
{
    remove_from "${1}" "${2}"
    [ -d "${2}" ] || return
    if [ -n "${!1}" ]
    then
        eval "export ${1}=\"${2}:${!1}\""
    else
        eval "export ${1}=\"${2}\""
    fi
}

1

Để hoàn thành / cải thiện câu trả lời được chấp nhận từ Tushar, bạn có thể:

  • tránh phải thoát khỏi dấu gạch chéo trong PATH bằng cách sử dụng dấu phân cách không gạch chéo
  • bỏ -etùy chọn, theo trang sed man : "Nếu không có tùy chọn -e, --expression, -f hoặc --file, thì đối số không phải tùy chọn đầu tiên được lấy làm tập lệnh sed để diễn giải."
  • sử dụng gcờ (toàn cầu) để xóa tất cả các lần xuất hiện

Cuối cùng, nó cho một cái gì đó như thế này:

PATH=$(echo "$PATH" | sed 's@:/home/wrong/dir$@@g')

0

Các câu trả lời hiện tại không giải quyết được vấn đề tương tự của tôi ở chỗ tôi cần xóa nhiều đường dẫn. Tất cả các đường dẫn này là thư mục con của một thư mục. Trong trường hợp đó, lớp lót này hoạt động với tôi: (giả sử mẫu đó là cygwin, loại bỏ tất cả các đường dẫn có chứa cygwin)

pattern=cygwin; export PATH=$(echo $PATH|tr ':' '\n'|sed "\#${pattern}#d" |tr '\n' ':')
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.