Menghapus direktori dari PATH

28

Saya mencoba untuk mengkompilasi wxWidgets menggunakan MingW, dan saya memiliki cygwin di jalan saya, yang tampaknya bertentangan. Jadi saya ingin menghapus /d/Programme/cygwin/bindari variabel PATH dan saya ingin tahu apakah ada cara yang elegan untuk melakukan ini.

Pendekatan naif adalah untuk menggemakannya ke file, menghapusnya secara manual dan sumbernya, tapi saya yakin ada pendekatan yang lebih baik untuk ini.

Devolus
sumber
2
Banyak teknik tercantum di sini: stackoverflow.com/questions/370047/…
slm

Jawaban:

23

Tidak ada alat standar untuk "mengedit" nilai $ PATH (yaitu "tambahkan folder hanya ketika itu belum ada" atau "hapus folder ini"). Anda hanya menjalankan:

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

yang akan untuk sesi saat ini, jika Anda ingin mengubahnya secara permanen, tambahkan ke .bashrc, bash.bashrc, / etc / profile - apa pun yang sesuai dengan kebutuhan sistem dan pengguna Anda. Namun jika Anda menggunakan BASH, Anda juga dapat melakukan hal berikut jika, katakanlah, Anda ingin menghapus direktori /home/wrong/dir/dari variabel PATH Anda, dengan asumsi itu pada akhirnya:

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

Jadi, dalam kasus Anda, Anda dapat menggunakan

PATH=$(echo "$PATH" | sed -e 's/:\/d\/Programme\/cygwin\/bin$//')
tusharmakkar08
sumber
1
Jika jalur yang dipermasalahkan adalah di awal variabel PATH, Anda harus mencocokkan titik dua di akhir. Ini adalah peringatan menjengkelkan yang mempersulit manipulasi generik mudah dari variabel PATH.
Graeme
4
Ketika berhadapan dengan begitu banyak garis miring, saya lebih suka mengubah pembatas regex /dengan sesuatu seperti |: PATH=$(echo "$PATH" | sed -e 's|:/d/Programme/cygwin/bin$||')untuk mencegah semua pelarian.
Matthias Kuhn
17

Dalam bash:

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

Jika Anda tidak menggunakan variabel perantara, Anda perlu melindungi /karakter di direktori untuk dihapus sehingga mereka tidak diperlakukan sebagai akhir dari teks pencarian.

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

Baris pertama dan ketiga ada untuk mengatur agar setiap komponen dari jalur pencarian dikelilingi oleh :, untuk menghindari casing khusus komponen pertama dan terakhir. Baris kedua menghapus komponen yang ditentukan.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
Terima kasih @Gilles, jawaban Anda mendorong saya untuk mencari solusi sendiri , yang hanya membutuhkan tiga manipulasi PATH daripada empat. * 8 ')
Mark Booth
8

Setelah mempertimbangkan pilihan lain yang disajikan di sini, dan tidak sepenuhnya memahami bagaimana beberapa dari mereka bekerja, saya mengembangkan path_removefungsi saya sendiri , yang saya tambahkan ke .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
}

Ini berakhir cukup dekat dengan solusi Gilles tetapi dibungkus sebagai fungsi bash yang dapat dengan mudah digunakan pada baris perintah.

Ini memiliki keuntungan bahwa sebagai fungsi bash berfungsi seperti program tanpa harus menjadi program di jalur, dan tidak memerlukan program eksternal untuk dijalankan, hanya manipulasi string bash.

Tampaknya cukup kuat, khususnya tidak berubah somepath:mypath/mysubpathmenjadi somepath/mysubpath: jika Anda menjalankan path_remove mypath, yang merupakan masalah yang saya miliki dengan path_removefungsi saya sebelumnya .

Penjelasan yang bagus tentang bagaimana manipulasi string bash bekerja dapat ditemukan di Advanced Bash-Scripting Guide .

Mark Booth
sumber
6

Jadi, dengan menggabungkan jawaban dari @gilles dan @ bruno-a (dan beberapa trik sed lainnya), saya membuat one-liner ini, yang akan menghapus (setiap) REMOVE_PART dari PATH, terlepas dari apakah itu terjadi di awal, tengah atau akhir PATH

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

Agak sulit, tapi senang bisa melakukannya dalam satu pukulan. Ini ;digunakan untuk bergabung bersama dua perintah sed terpisah:

  • s@:$REMOVE_PART:@:@g(yang menggantikan :$REMOVE_PART:dengan tunggal :)
  • s@^:\(.*\):\$@\1@ (yang menghapus tanda titik dua utama dan akhir yang kami tambahkan dengan perintah echo)

Dan di sepanjang baris yang serupa, saya baru saja berhasil membuat satu-liner ini untuk menambahkan ADD_PART ke PATH, hanya jika PATH belum mengandungnya

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

Ubah bagian terakhir menjadi echo "$PATH:$ADD_PART"jika Anda ingin menambahkan ADD_PART ke akhir PATH daripada ke awal.

...

... atau untuk membuatnya lebih mudah, buat skrip yang disebut remove_path_partdengan konten

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

dan sebuah skrip yang disebut prepend_path_partdengan isinya

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

dan sebuah skrip yang disebut append_path_partdengan isinya

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

buat semuanya dapat dieksekusi, lalu panggil mereka seperti:

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

Rapi, bahkan jika saya mengatakannya sendiri :-)

Lurchman
sumber
Saya suka saran, terutama gagasan dengan skrip.
Devolus
3

Lebih sederhana satu liner.

export PATH = `echo $ PATH | tr ":" "\ n" | grep -v "anaconda" | tr "\ n" ":" `

pengguna332870
sumber
2

Merupakan latihan yang menarik untuk menulis fungsi bash untuk menghapus direktori dari variabel path.

Berikut adalah beberapa fungsi yang saya gunakan dalam file .bash * saya untuk menambahkan / menambahkan direktori ke path. Mereka memiliki kebajikan menghapus entri duplikat, jika ada, dan bekerja dengan segala jenis variabel jalur yang dipisahkan titik dua (PATH, MANPATH, INFOPATH, ...). fungsi remove_from menghapus direktori.

# {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\"
}
Greg Tarsa
sumber
2

Di bawah ini adalah kode revisi dari solusi Greg Tarsa. Hanya perintah built-in bash yang digunakan di sini. Dengan demikian, ini akan menghemat banyak panggilan sistem 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
}
Jie Gong
sumber
1

Untuk melengkapi / meningkatkan jawaban yang diterima dari Tushar, Anda dapat:

  • menghindari harus menghindari garis miring pada PATH dengan menggunakan pembatas non-garis miring
  • hilangkan -eopsi, sesuai halaman manual sed : "Jika opsi no -e, --expression, -f, atau --file diberikan, maka argumen non-opsi pertama diambil sebagai skrip sed untuk ditafsirkan."
  • gunakan gbendera (global) untuk menghapus semua kejadian

Pada akhirnya, ia memberikan sesuatu seperti ini:

PATH=$(echo "$PATH" | sed 's@:/home/wrong/dir$@@g')
Bruno A.
sumber
0

Jawaban saat ini tidak menyelesaikan masalah saya yang serupa karena saya perlu menghapus banyak jalur. Semua jalur ini adalah sub-direktori dari satu direktori. Jika demikian, one-liner ini berfungsi untuk saya: (misalkan polanya adalah cygwin, yaitu menghapus semua jalur yang berisi cygwin)

pattern=cygwin; export PATH=$(echo $PATH|tr ':' '\n'|sed "\#${pattern}#d" |tr '\n' ':')
Penghe Geng
sumber