การลบไดเรกทอรีจาก PATH


28

ฉันพยายามรวบรวม wxWidgets โดยใช้ MingW และฉันมี cygwin ในเส้นทางของฉันซึ่งดูเหมือนว่าจะขัดแย้งกัน ดังนั้นฉันต้องการลบออก/d/Programme/cygwin/binจากตัวแปร PATH และฉันสงสัยว่ามีวิธีที่สง่างามในการทำเช่นนี้หรือไม่

วิธีการที่ไร้เดียงสาจะสะท้อนไปยังไฟล์ลบออกด้วยตัวเองและส่งมัน แต่ฉันคิดว่ามันมีวิธีการที่ดีกว่า


2
มีหลายเทคนิคที่ระบุไว้ที่นี่: stackoverflow.com/questions/370047/…
slm

คำตอบ:


23

ไม่มีเครื่องมือมาตรฐานในการ "แก้ไข" ค่าของ $ PATH (เช่น "เพิ่มโฟลเดอร์เมื่อไม่มีอยู่แล้ว" หรือ "ลบโฟลเดอร์นี้") คุณเพิ่งดำเนินการ:

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

นั่นคือสำหรับเซสชันปัจจุบันหากคุณต้องการเปลี่ยนเพิ่มอย่างถาวรไปยัง. bashrc, bash.bashrc, / etc / profile ใด ๆ ก็ตามที่เหมาะกับระบบและความต้องการของผู้ใช้ของคุณ อย่างไรก็ตามหากคุณใช้ BASH คุณสามารถทำสิ่งต่อไปนี้ได้เช่นถ้าคุณต้องการลบไดเรกทอรี/home/wrong/dir/ออกจากตัวแปร PATH ของคุณโดยสมมติว่ามันอยู่ท้ายที่สุด:

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

ดังนั้นในกรณีของคุณคุณอาจใช้

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

1
หากเส้นทางที่เป็นปัญหาอยู่ที่จุดเริ่มต้นของตัวแปร PATH คุณต้องจับคู่โคลอนในตอนท้าย นี่เป็นข้อแม้ที่น่ารำคาญซึ่งทำให้การเปลี่ยนแปลงตัวแปร PATH ง่ายขึ้น
แกรม

4
เมื่อต้องรับมือกับเครื่องหมายทับหลาย ๆ อันฉันต้องการเปลี่ยนตัวคั่น regex /ด้วยวิธี|ดังนี้PATH=$(echo "$PATH" | sed -e 's|:/d/Programme/cygwin/bin$||')เพื่อป้องกันการหลบหนีทั้งหมด
Matthias Kuhn

17

ในทุบตี:

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

หากคุณไม่ได้ใช้ตัวแปรกลางคุณจะต้องป้องกัน/ตัวอักษรในไดเรกทอรีเพื่อลบเพื่อไม่ให้ถือว่าเป็นจุดสิ้นสุดของข้อความค้นหา

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

บรรทัดแรกและบรรทัดที่สามจะมีการจัดเรียงสำหรับทุกองค์ประกอบของเส้นทางการค้นหาที่จะถูกล้อมรอบ:เพื่อหลีกเลี่ยงการใส่ปลอกพิเศษและองค์ประกอบสุดท้าย บรรทัดที่สองลบองค์ประกอบที่ระบุ


ขอบคุณ @Gilles คำตอบของคุณทำให้ฉันมากับโซลูชันของฉันเองซึ่งต้องการเพียงแค่การปรับแต่ง PATH สามครั้งแทนที่จะเป็นสี่ครั้ง * 8 ')
ทำเครื่องหมายบูธ

8

หลังจากพิจารณาตัวเลือกอื่น ๆ ที่นำเสนอที่นี่และไม่เข้าใจว่าพวกเขาทำงานอย่างไรฉันพัฒนาpath_removeฟังก์ชั่นของตัวเองซึ่งฉันได้เพิ่มเข้าไปใน.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
}

จบลงด้วยความใกล้ชิดกับวิธีแก้ปัญหาของ Gillesแต่ฟังก์ชั่นทุบตีซึ่งสามารถใช้งานได้ง่ายบนบรรทัดคำสั่ง

มันมีข้อดีที่เป็นฟังก์ชั่นทุบตีมันทำงานเหมือนโปรแกรมโดยไม่จำเป็นต้องเป็นโปรแกรมบนพา ธ และไม่ต้องการให้โปรแกรมภายนอกใด ๆ ทำงานได้เพียงแค่จัดการกับสตริงของ bash

มันดูค่อนข้างแข็งแกร่งโดยเฉพาะอย่างยิ่งมันไม่ได้เปลี่ยนsomepath:mypath/mysubpathเป็นsomepath/mysubpath: ถ้าคุณเรียกใช้path_remove mypathซึ่งเป็นปัญหาที่ฉันมีกับpath_removeฟังก์ชั่นก่อนหน้าของฉัน

คำอธิบายที่ดีของวิธีสตริงทุบตีงานการจัดการที่สามารถพบได้ในทุกประเภททุบตี Scripting คู่มือ


6

ดังนั้นการรวมคำตอบจาก @gilles และ @ bruno-a (และกลอุบายอื่น ๆ อีกสองสามรายการ) ฉันจึงคิดคำตอบหนึ่งซับซึ่งจะลบ (ทุก ๆ ) REMOVE_PART ออกจาก PATH โดยไม่คำนึงว่ามันจะเกิดขึ้นที่จุดเริ่มต้นหรือไม่ กึ่งกลางหรือจุดสิ้นสุดของ PATH

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

มันค่อนข้างเทอะทะ แต่ก็ดีที่สามารถทำได้ในการเข้าชมครั้งเดียว การ;ใช้เพื่อรวมคำสั่ง sed สองคำด้วยกัน:

  • s@:$REMOVE_PART:@:@g(ซึ่งแทนที่:$REMOVE_PART:ด้วยอันเดียว:)
  • s@^:\(.*\):\$@\1@ (ซึ่งปิดโคลอนนำหน้าและต่อท้ายที่เราเพิ่มด้วยคำสั่ง echo)

และตามบรรทัดที่คล้ายกันฉันเพิ่งจะเกิดขึ้นกับหนึ่งซับสำหรับการเพิ่ม ADD_PART ไปที่เส้นทางเฉพาะในกรณีที่เส้นทางไม่ได้มีอยู่แล้ว

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')

เปลี่ยนส่วนสุดท้ายเป็นecho "$PATH:$ADD_PART"หากคุณต้องการเพิ่ม ADD_PART ที่ส่วนท้ายของ PATH แทนที่จะเป็นจุดเริ่มต้น

...

... หรือเพื่อให้ง่ายยิ่งขึ้นให้สร้างสคริปต์ที่remove_path_partมีเนื้อหา

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

และสคริปต์ที่prepend_path_partมีเนื้อหา

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

และสคริปต์ที่append_path_partมีเนื้อหา

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

ทำให้พวกเขาทั้งหมดที่ปฏิบัติการได้แล้วเรียกพวกเขาเช่น:

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

เรียบร้อยแม้ว่าฉันจะพูดอย่างนั้น :-)


ฉันชอบคำแนะนำโดยเฉพาะความคิดกับสคริปต์
Devolus


2

มันเป็นแบบฝึกหัดที่น่าสนใจในการเขียนฟังก์ชั่นทุบตีเพื่อลบไดเรกทอรีออกจากตัวแปรพา ธ

นี่คือฟังก์ชั่นบางอย่างที่ฉันใช้ในไฟล์. bash * ของฉันเพื่อผนวก / เพิ่มไดเรกทอรีลงในพา ธ พวกมันมีข้อดีของการลบรายการที่ซ้ำกันถ้ามีและทำงานกับตัวแปรพา ธ ที่คั่นด้วยโคลอนชนิดใดก็ได้ (PATH, MANPATH, INFOPATH, ... ) ฟังก์ชั่น remove_from ลบไดเรกทอรี

# {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

ด้านล่างเป็นรหัสที่ปรับปรุงใหม่จากโซลูชันของ Greg Tarsa ใช้คำสั่ง bash build-in เท่านั้น ดังนั้นมันจะบันทึกการเรียกระบบ 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

เพื่อให้สมบูรณ์ / ปรับปรุงคำตอบที่ยอมรับจาก Tushar คุณสามารถ:

  • หลีกเลี่ยงการใช้เครื่องหมายสแลชใน PATH โดยใช้ตัวคั่นที่ไม่ใช่สแลช
  • ละเว้น-eตัวเลือกตามหน้า man sed : "หากไม่มีตัวเลือก -e, - expression, -f หรือ --file ดังนั้นอาร์กิวเมนต์ที่ไม่ใช่ตัวเลือกแรกจะถูกใช้เป็นสคริปต์ sed เพื่อตีความ"
  • ใช้gแฟล็ก (โกลบอล) เพื่อลบการเกิดขึ้นทั้งหมด

ในท้ายที่สุดมันให้อะไรเช่นนี้:

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

0

คำตอบปัจจุบันไม่ได้แก้ปัญหาที่คล้ายกันของฉันในที่ฉันต้องลบหลายเส้นทาง พา ธ ทั้งหมดเหล่านี้เป็นไดเรกทอรีย่อยของไดเรกทอรีเดียว ในกรณีนั้นหนึ่งซับนี้ใช้ได้กับฉัน: (สมมติว่ารูปแบบคือcygwinลบเส้นทางทั้งหมดที่มีcygwin)

pattern=cygwin; export PATH=$(echo $PATH|tr ':' '\n'|sed "\#${pattern}#d" |tr '\n' ':')
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.