O de manera más general, ¿cómo elimino un elemento de una lista separada por dos puntos en una variable de entorno Bash?
Pensé que había visto una forma sencilla de hacer esto hace años, utilizando las formas más avanzadas de expansión variable Bash, pero si es así, lo he perdido. Una búsqueda rápida en Google arrojó sorprendentemente pocos resultados relevantes y ninguno que yo llamaría "simple" o "elegante". Por ejemplo, dos métodos que usan sed y awk, respectivamente:
PATH=$(echo $PATH | sed -e 's;:\?/home/user/bin;;' -e 's;/home/user/bin:\?;;')
PATH=!(awk -F: '{for(i=1;i<=NF;i++){if(!($i in a)){a[$i];printf s$i;s=":"}}}'<<<$PATH)
¿No existe nada sencillo? ¿Hay algo análogo a una función split () en Bash?
Actualización:
Parece que necesito disculparme por mi pregunta intencionalmente vaga; Estaba menos interesado en resolver un caso de uso específico que en provocar una buena discusión. ¡Afortunadamente lo conseguí!
Aquí hay algunas técnicas muy inteligentes. Al final, agregué las siguientes tres funciones a mi caja de herramientas. La magia ocurre en path_remove, que se basa en gran medida en el uso inteligente de awk
la variable RS de Martin York .
path_append () { path_remove $1; export PATH="$PATH:$1"; }
path_prepend () { path_remove $1; export PATH="$1:$PATH"; }
path_remove () { export PATH=`echo -n $PATH | awk -v RS=: -v ORS=: '$0 != "'$1'"' | sed 's/:$//'`; }
El único problema real que hay es el uso de sed
para eliminar el colon posterior. Sin embargo, teniendo en cuenta lo sencillo que es el resto de la solución de Martin, ¡estoy bastante dispuesto a vivir con ella!
Pregunta relacionada: ¿Cómo manipulo los elementos $ PATH en los scripts de shell?
fuente
WORK=`echo -n ${1} | awk -v RS=: -v ORS=: '$0 != "'${3}'"' | sed 's/:$//'`; eval "export ${2}=${WORK}"
pero debe llamarlo comofunc $VAR VAR pattern
(basado en @ martin-york y @ andrew-aylett)Respuestas:
Un minuto con awk:
Editar: responde a los comentarios a continuación:
Editar en respuesta a un problema de seguridad: (eso no es relevante para la pregunta)
Esto elimina los dos puntos finales que quedan al eliminar las últimas entradas, lo que efectivamente se agregaría
.
a su ruta.fuente
PATH
variable de hace , como una norma especial, denotan directorio actual en todas las cáscaras de Unix desde al menos V7 Unix de 1979. Todavía hace enbash
. Consulte el manual o pruébelo usted mismo.Mi sucio truco:
fuente
Dado que el gran problema con la sustitución son los casos finales, ¿qué tal si los casos finales no son diferentes de los otros casos? Si la ruta ya tiene dos puntos al principio y al final, simplemente podríamos buscar la cadena deseada envuelta con dos puntos. Tal como está, podemos agregar fácilmente esos dos puntos y eliminarlos después.
Pure bash :).
fuente
WORK
y,PATH
ya que la expansión de la variable ocurre después de que la línea se analiza en secciones para la asignación de variables y la ejecución de comandos.REMOVE
es posible que deba citarse, o simplemente puede colocar su cadena directamente en el reemplazo si es una constante.Aquí está la solución más simple que puedo idear:
El ejemplo anterior eliminará cualquier elemento en $ PATH que contenga "usr". Puede reemplazar "* usr *" con "/ home / user / bin" para eliminar solo ese elemento.
actualizar por sschuberth
Aunque creo que los espacios en un
$PATH
son una idea horrible , aquí hay una solución que lo maneja:o
fuente
Aquí hay un resumen que, a pesar de las respuestas actualmente aceptadas y mejor calificadas , no agrega caracteres invisibles a PATH y puede hacer frente a rutas que contienen espacios:
Personalmente, también encuentro esto fácil de leer / entender, y solo involucra comandos comunes en lugar de usar awk.
fuente
export PATH=$(p=$(echo $PATH | tr ":" "\0" | grep -v -z "/cygwin/" | tr "\0" ":"); echo ${p%:})
(aunque podría decirse, es posible que desee preguntarse por qué necesita esto, si lo necesita :))grep -v "^/path/to/remove\$"
ogrep -v -x "/path/to/remove"
tr
es más común queawk
? ;)tr
lugar de un intérpreteawk
.echo "..."
conprintf "%s" "..."
para que funcione en rutas-e
similares. Ver stackoverflow.com/a/49418406/102441Aquí hay una solución que:
IFS
,elimina todas las apariciones del argumento en
PATH
.fuente
Lo saqué de mi archivo .bashrc. Cuando juegas con PATH y se pierde, awk / sed / grep deja de estar disponible :-)
fuente
La mejor opción de bash puro que he encontrado hasta ahora es la siguiente:
Esto se basa en la respuesta no del todo correcta para Agregar directorio a $ PATH si aún no está en Superusuario.
fuente
removePath () { PATH=${PATH/":$1"/}; PATH=${PATH/"$1:"/}; }
$PATH
contiene una subcarpeta de la ruta de destino (es decir, que se eliminará). Por ejemplo:a:abc/def/bin:b
->a/bin:b
, cuándoabc/def
se eliminará.Acabo de usar las funciones en la distribución bash, que aparentemente han estado ahí desde 1991. Estas todavía están en el paquete bash-docs en Fedora, y solían usarse
/etc/profile
, pero ya no ...fuente
Escribí una respuesta a esto aquí (usando awk también). ¿Pero no estoy seguro de que sea eso lo que estás buscando? Al menos me parece claro lo que hace, en lugar de intentar encajar en una línea. Sin embargo, para un delineador simple que solo elimina cosas, recomiendo
Reemplazar es
o (más corto pero menos legible)
De todos modos, para la misma pregunta y muchas respuestas útiles, consulte aquí .
fuente
awk '$0 !~ "/bin"'
. Es decir, mantenga las líneas que no contengan '/ bin' con el operador awk!~
.Bueno, en bash, ya que admite expresiones regulares, simplemente haría:
fuente
Me gustan las tres funciones que se muestran en la actualización de @ BenBlank a su pregunta original. Para generalizarlos, utilizo una forma de 2 argumentos, lo que me permite establecer PATH o cualquier otra variable de entorno que desee:
Ejemplos de uso:
Tenga en cuenta que también agregué algunas comillas para permitir el procesamiento adecuado de los nombres de ruta que contienen espacios.
fuente
¿Qué es más elegante que awk?
¡Pitón! Es una solución más legible y fácil de mantener, y es fácil de inspeccionar para ver que realmente está haciendo lo que quieres.
Digamos que desea eliminar el primer elemento de ruta.
(En lugar de canalizar desde
echo
,os.getenv['PATH']
sería un poco más corto y proporcionaría el mismo resultado que el anterior, pero me preocupa que Python pueda hacer algo con esa variable de entorno, por lo que probablemente sea mejor canalizarlo directamente desde el entorno que le interesa. .)De manera similar para eliminar del final:
Para hacer estas funciones de shell reutilizables que puede, por ejemplo, pegar en su archivo .bashrc:
fuente
Sí, poner dos puntos al final de PATH, por ejemplo, hace que eliminar una ruta sea un poco menos torpe y propenso a errores.
fuente
Si le preocupa eliminar duplicados en $ PATH, la forma más elegante, en mi humilde opinión, sería no agregarlos en primer lugar. En 1 línea:
$ carpeta puede ser reemplazada por cualquier cosa y puede contener espacios ("/ inicio / usuario / mis documentos")
fuente
La solución bash pura más elegante que he encontrado hasta la fecha:
fuente
La mayor parte de las otras soluciones propuestas se basan únicamente en la coincidencia de cadenas y no toman en cuenta los segmentos de trazado que contienen nombres especiales como
.
,..
o~
. La función bash siguiente resuelve cadenas de directorio en su argumento y en segmentos de ruta para encontrar coincidencias de directorio lógicas así como coincidencias de cadenas.Prueba:
fuente
Linux from Scratch define tres funciones Bash en
/etc/profile
:Ref: http://www.linuxfromscratch.org/blfs/view/svn/postlfs/profile.html
fuente
Sé que esta pregunta se refiere a BASH, que todos deberían preferir, pero como disfruto de la simetría y, a veces, debo usar "csh", construí el equivalente a "path_prepend ()", "path_append ()" y "path_remove () "elegante solución anterior.
La esencia es que "csh" no tiene funciones, así que pongo pequeños scripts de shell en mi directorio bin personal que actúan como las funciones. Creo alias a FUENTE esos scripts para hacer los cambios de variable de entorno designados.
~ / bin / _path_remove.csh:
~ / bin / _path_append.csh:
~ / bin / _path_prepend.csh:
~ / bin / .cshrc:
Puedes usarlos así ...
fuente
Dado que esto tiende a ser bastante problemático, ya que NO HAY una forma elegante, recomiendo evitar el problema reorganizando la solución: construya su PATH en lugar de intentar derribarlo.
Podría ser más específico si supiera el contexto real de su problema. Mientras tanto, usaré una compilación de software como contexto.
Un problema común con las compilaciones de software es que se rompe en algunas máquinas, en última instancia debido a cómo alguien ha configurado su shell predeterminado (PATH y otras variables de entorno). La solución elegante es hacer que sus scripts de compilación sean inmunes especificando completamente el entorno de shell. Codifique sus scripts de compilación para establecer la RUTA y otras variables de entorno en función de las piezas de ensamblaje que controle, como la ubicación del compilador, bibliotecas, herramientas, componentes, etc. Haga que cada elemento configurable sea algo que pueda configurar, verificar y luego utilícelo de manera apropiada en su guión.
Por ejemplo, tengo una compilación de Java dirigida a WebLogic basada en Maven que heredé de mi nuevo empleador. El script de compilación es conocido por ser frágil, y otro empleado nuevo y yo pasamos tres semanas (no a tiempo completo, solo aquí y allá, pero todavía muchas horas) haciendo que funcione en nuestras máquinas. Un paso esencial fue que tomé el control de PATH para saber exactamente qué Java, qué Maven y qué WebLogic se estaba invocando. Creé variables de entorno para señalar cada una de esas herramientas, luego calculé la RUTA en función de esas y algunas otras. Técnicas similares domesticaron las otras configuraciones configurables, hasta que finalmente creamos una compilación reproducible.
Por cierto, no use Maven, Java está bien y solo compre WebLogic si absolutamente necesita su agrupación en clústeres (pero por lo demás no, y especialmente no sus características propietarias).
Los mejores deseos.
fuente
PATH
. Claro, podría construir uno propio, pero cada vez que su administrador mueva algo, debe averiguar dónde lo puso. Eso frustra el propósito de tener un administrador.Al igual que con @litb, contribuí con una respuesta a la pregunta " ¿Cómo manipulo los elementos $ PATH en scripts de shell? ", Así que mi respuesta principal está ahí.
La funcionalidad 'dividir' en
bash
y otros derivados del shell Bourne se logra de la manera más prolija con$IFS
el separador entre campos. Por ejemplo, para establecer los argumentos posicionales ($1
,$2
, ...) a los elementos de PATH, uso:Funcionará bien siempre que no haya espacios en $ PATH. Hacer que funcione para elementos de ruta que contienen espacios no es un ejercicio trivial, dejado para el lector interesado. Probablemente sea más sencillo tratar con un lenguaje de programación como Perl.
También tengo un script,
clnpath
que uso mucho para configurar mi PATH. Lo documenté en la respuesta a " Cómo evitar duplicar la variable PATH en csh ".fuente
Lo que hace que este problema sea molesto son los casos de poste de cerca entre el primer y el último elemento. El problema se puede resolver elegantemente cambiando IFS y usando una matriz, pero no sé cómo volver a introducir los dos puntos una vez que la ruta se convierte en forma de matriz.
Aquí hay una versión un poco menos elegante que elimina un directorio del
$PATH
uso exclusivo de la manipulación de cadenas. Lo he probado.fuente
Aquí hay un resumen de Perl:
La
$a
variable obtiene la ruta a eliminar. Los comandoss
(sustitutos) yprint
operan implícitamente en la$_
variable.fuente
Buenas cosas aquí. Yo uso este para evitar agregar incautos en primer lugar.
fuente
case ":$PATH:" in (*:"$nodup":*) ;; (*) PATH="$PATH:$nodup" ;; esac
Con el globbing extendido habilitado, es posible hacer lo siguiente:
fuente
Una sola línea de globbing extendido (bueno, más o menos):
Parece que no hay necesidad de escapar de las barras en $ 1.
fuente
Añadiendo dos puntos a PATH también podríamos hacer algo como:
fuente
En path_remove_all (por proxy):
fuente
Si bien este es un hilo muy antiguo, pensé que esta solución podría ser de interés:
lo encontré en esta publicación de blog . Creo que este es el que más me gusta :)
fuente
Adopté un enfoque ligeramente diferente al de la mayoría de las personas aquí y me centré específicamente en la manipulación de cuerdas, así:
Lo anterior es un ejemplo simplificado de las funciones finales que uso. También he creado
path_add_before
ypath_add_after
permitiéndote insertar una ruta antes / después de una ruta especificada que ya está en PATH.El conjunto completo de funciones está disponible en path_helpers.sh en mis archivos de puntos . Son totalmente compatibles con la eliminación / adición / anteposición / inserción al principio / medio / final de la cadena PATH.
fuente