Eliminar un directorio de la RUTA

28

Estoy tratando de compilar wxWidgets usando MingW, y tengo cygwin en mi camino, lo que parece estar en conflicto. Por lo tanto, me gustaría eliminar /d/Programme/cygwin/binde la variable PATH y me pregunto si hay alguna forma elegante de hacerlo.

El enfoque ingenuo sería hacer eco en un archivo, eliminarlo manualmente y obtenerlo, pero apuesto a que hay un mejor enfoque para esto.

Devolus
fuente
2
Aquí se enumeran muchas técnicas: stackoverflow.com/questions/370047/…
slm

Respuestas:

23

No hay herramientas estándar para "editar" el valor de $ PATH (es decir, "agregar carpeta solo cuando aún no existe" o "eliminar esta carpeta"). Simplemente ejecutas:

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

eso sería para la sesión actual, si desea cambiar permanentemente, agréguelo a cualquier .bashrc, bash.bashrc, / etc / profile, lo que se ajuste a las necesidades de su sistema y usuario. Sin embargo, si está utilizando BASH, también puede hacer lo siguiente si, por ejemplo, desea eliminar el directorio /home/wrong/dir/de su variable PATH, suponiendo que esté al final:

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

Entonces en tu caso puedes usar

PATH=$(echo "$PATH" | sed -e 's/:\/d\/Programme\/cygwin\/bin$//')
tusharmakkar08
fuente
1
Si la ruta en cuestión se encuentra al comienzo de la variable PATH, debe hacer coincidir los dos puntos al final. Esta es una advertencia molesta que complica las manipulaciones genéricas fáciles de las variables PATH.
Graeme
44
Cuando trato con tantas barras, prefiero cambiar el delimitador de expresiones regulares /con algo como |: PATH=$(echo "$PATH" | sed -e 's|:/d/Programme/cygwin/bin$||')para evitar que se escapen.
Matthias Kuhn el
17

En bash:

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

Si no utiliza una variable intermedia, debe proteger los /caracteres del directorio para eliminarlos de modo que no se traten como el final del texto de búsqueda.

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

La primera y la tercera línea están allí para organizar cada componente de la ruta de búsqueda para que esté rodeado :, para evitar una carcasa especial del primer y último componente. La segunda línea elimina el componente especificado.

Gilles 'SO- deja de ser malvado'
fuente
Gracias @Gilles, su respuesta me impulsó a encontrar mi propia solución , que solo requiere tres manipulaciones de PATH en lugar de cuatro. * 8 ')
Mark Booth
8

Después de considerar otras opciones presentadas aquí, y no entender completamente cómo funcionaban algunas de ellas, desarrollé mi propia path_removefunción, que agregué a mi .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
}

Esto terminó bastante cerca de la solución de Gilles, pero concluyó como una función bash que podría usarse fácilmente en la línea de comando.

Tiene las ventajas de que, como función bash, funciona como un programa sin necesidad de ser un programa en la ruta, y no requiere ningún programa externo para ejecutarse, solo la manipulación de cadenas bash.

Parece bastante robusto, en particular no se convierte somepath:mypath/mysubpathen somepath/mysubpath: si ejecuta path_remove mypath, que era un problema que tuve con mi path_removefunción anterior .

Puede encontrar una excelente explicación de cómo funciona la manipulación de cadenas de bash en la Guía avanzada de secuencias de comandos Bash .

Mark Booth
fuente
6

Entonces, combinando las respuestas de @gilles y @ bruno-a (y un par de otros trucos de sed) se me ocurrió este one-liner, que eliminará (cada) REMOVE_PART de PATH, independientemente de si ocurre al principio, medio o final de la RUTA

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

Es un poco difícil de manejar, pero es bueno poder hacerlo de un solo golpe. El ;se utiliza para unir los dos comandos sed separados:

  • s@:$REMOVE_PART:@:@g(que reemplaza :$REMOVE_PART:con una sola :)
  • s@^:\(.*\):\$@\1@ (que elimina los dos puntos iniciales y finales que agregamos con el comando echo)

Y a lo largo de líneas similares, acabo de llegar a esta línea para agregar un ADD_PART a la RUTA, solo si la RUTA aún no lo contiene

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

Cambie la última parte a echo "$PATH:$ADD_PART"si desea agregar ADD_PART al final de PATH en lugar de al inicio.

...

... o para hacer esto aún más fácil, cree un script llamado remove_path_partcon el contenido

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

y un script llamado prepend_path_partcon el contenido

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

y un script llamado append_path_partcon el contenido

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

hacerlos todos ejecutables y luego llamarlos como:

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

Genial, incluso si lo digo yo mismo :-)

Lurchman
fuente
Me gusta la sugerencia, especialmente la idea con los guiones.
Devolus el
3

Mucho más simple un revestimiento.

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

usuario332870
fuente
2

Es un ejercicio interesante escribir una función bash para eliminar un directorio de una variable de ruta.

Estas son algunas funciones que uso en mis archivos .bash * para agregar / anteponer directorios a las rutas. Tienen la virtud de eliminar entradas duplicadas, si las hay, y funcionan con cualquier tipo de variable de ruta separada por dos puntos (PATH, MANPATH, INFOPATH, ...). la función remove_from elimina el directorio.

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

A continuación se muestra el código revisado de la solución de Greg Tarsa. Aquí solo se usan los comandos de bash build-in. Por lo tanto, ahorrará muchas llamadas al sistema 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
fuente
1

Para completar / mejorar la respuesta aceptada de Tushar, puede:

  • evite tener que escapar de las barras en la RUTA utilizando delimitadores sin barra
  • omita la -eopción, según la página de manual de sed : "Si no se da la opción -e, --expression, -f o --file, el primer argumento sin opción se toma como el script sed para interpretar".
  • use la gbandera (global) para eliminar todas las ocurrencias

Al final, da algo como esto:

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

Las respuestas actuales no resuelven mi problema similar, ya que necesito eliminar varias rutas. Todas estas rutas son subdirectorios de un único directorio. En ese caso, este one-liner funciona para mí: (supongamos que el patrón es cygwin, es decir, eliminar todas las rutas que contiene cygwin)

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