¿Cuál es la forma más sencilla de eliminar una barra al final de cada parámetro?

98

¿Cuál es la forma más sencilla de eliminar una barra al final de cada parámetro en la matriz '$ @', de modo que rsynccopie los directorios por nombre?

rsync -a --exclude='*~' "$@" "$dir"

Se ha cambiado el título para aclararlo. Para comprender los comentarios y responder sobre múltiples barras inclinadas, consulte el historial de ediciones.

sid_com
fuente
2
posible duplicado de Eliminar barra oblicua del final de una variable
Warren Dew

Respuestas:

160

Puede utilizar la ${parameter%word}expansión que se detalla aquí . Aquí hay un script de prueba simple que demuestra el comportamiento:

#!/bin/bash

# Call this as:
#   ./test.sh one/ two/ three/ 
#
# Output:
#  one two three

echo ${@%/}
Sean Bright
fuente
35
+1: Para ser muy pedante, eso eliminará una sola barra, no todas las barras finales. Para eliminar cualquier número de barras al final:shopt -s extglob; echo "${@%%+(/)}"
Glenn Jackman
24
Advertencia: es posible que no desee eliminar las barras inclinadas en todos los casos. Si se proporciona "/" como argumento, eliminar la barra inclinada tendrá ... consecuencias desafortunadas.
Gordon Davisson
13
PROTIP: Combine tr -s /con expresión regular variable para eliminar las barras repetidas y luego elimine la barra final. pDIR=$(echo //some///badly/written///dir////// | tr -s /); DIR=${DIR%/}
Dave
1
De Verdad? En una fiesta de aviso, ejecución set -- one///// two// three four/; shopt -s extglob; echo "${@%%+(/)}"y dime lo que ves
Glenn Jackman
1
@twalberg Aprecio los "protips" que no son solo respuestas alternativas a la pregunta de OP en los hilos de comentarios.
Kyle Strand
39

La respuesta aceptada recortará UNA barra al final.

Una forma de recortar varias barras al final es la siguiente:

VALUE=/looks/like/a/path///

TRIMMED=$(echo $VALUE | sed 's:/*$::')

echo $VALUE $TRIMMED

Qué salidas:

/looks/like/a/path/// /looks/like/a/path
Chris Johnson
fuente
1
No olvide citar sus variables, en caso de que contengan espacios en blanco: TRIMMED=$(echo "$VALUE" | sed 's:/*$::')
tetsujin
1
En realidad, eso no es necesario dentro de la $()construcción. Sin embargo, también es inofensivo :) por lo que probablemente sea una buena práctica usar comillas dobles como "$VALUE"para no tener que decidir cuándo y cuándo no usar las comillas dobles.
Chris Johnson
¿Alguna forma de combinar esto con una captura anterior? Quiero eliminar el protocolo y (si está presente) la barra diagonal de una URL, pero echo "https://www.example.com/foo/" | sed -e 's|https*://\(.*\)/*$|\1|'no funciona (ya que el grupo de captura también coincide con la barra final, supongo). Puedo hacerlo con dos comandos: echo "https://www.example.com/foo/" | sed -e 's|https*://\(.*\)$|\1|' -e 's|/*$||'pero me preguntaba si se podría hacer con uno.
Adam
Esta respuesta funcionó mejor para mí con un archivo de entrada muy grande. Un simple sed 's:/*$::' < in.txt > out.txthace el trabajo en segundos
MitchellK
22

Esto funciona para mi: ${VAR%%+(/)}

Como se describe aquí http://wiki.bash-hackers.org/syntax/pattern

Es posible que deba configurar la opción de shell extglob. No puedo verlo habilitado para mí, pero aún funciona

Iván
fuente
2
Para consultar una configuración: shopt extglobsin opciones
glenn jackman
Este es el lenguaje de patrones extendido y debe configurarlo extglob.
ingyhere
1
Esto no funciona en el bash integrado de Mac OS X. La solución de Sean Bright anterior lo hace:${VAR%/}
Alec Jacobson
13

realpathresuelve el camino dado. Entre otras cosas, también elimina las barras inclinadas. Úselo -spara evitar los siguientes enlaces SIM

DIR=/tmp/a///
echo $(realpath -s $DIR)
# output: /tmp/a
czerny
fuente
1
Requiere que todos los nodos de la ruta existan excepto el último. Si el usuario arroja algún camino de inexistencia, realpathfallará.
Livy
2
@Livy realpath --canonicalize-missingfunciona absolutamente correctamente con cualquier parte no existente de la ruta
maoizm
y falta realpath en algunas plataformas :-(
Mark Ribau
8

Para su información, agregué estas dos funciones a mi .bash_profilebasado en las respuestas encontradas en SO. Como dijo Chris Johnson, todas las respuestas que usan ${x%/}eliminan solo una barra, estas funciones harán lo que dicen, espero que esto sea útil.

rem_trailing_slash() {
    echo "$1" | sed 's/\/*$//g'
}

force_trailing_slash() {
    echo "$(rem_trailing_slash "$1")/"
}
Jonathan H
fuente
4

En zsh puedes usar el :amodificador.

export DIRECTORY='/some//path/name//'

echo "${DIRECTORY:a}"

=> /some/path/name

Esto actúa como realpathpero no falla con archivos / directorios faltantes como argumento.

Nicolai Fröhlich
fuente