Tengo un script de shell con este código:
var=`hg st -R "$path"`
if [ -n "$var" ]; then
echo $var
fi
Pero el código condicional siempre se ejecuta, porque hg st
siempre imprime al menos un carácter de nueva línea.
- ¿Hay una manera simple de eliminar espacios en blanco
$var
(comotrim()
en PHP )?
o
- ¿Existe una forma estándar de tratar este problema?
Podría usar sed o AWK , pero me gustaría pensar que hay una solución más elegante para este problema.
$ var=$(echo)
$ [ -n $var ]; echo $? #undesired test return
0
$ [[ -n $var ]]; echo $?
1
echo " This is a string of char " | xargs
. Si por el contrario tiene una comilla simple en el texto se puede hacer lo siguiente:echo " This i's a string of char " | xargs -0
. Tenga en cuenta que menciono el último de xargs (4.6.0)test=`echo`; if [ -n "$test" ]; then echo "Not empty"; fi
, sin embargo, esto lo harátest=`echo "a"`; if [ -n "$test" ]; then echo "Not empty"; fi
, por lo que debe haber más que una nueva línea al final.echo $A | sed -r 's/( )+//g'
;Respuestas:
Definamos una variable que contenga espacios en blanco iniciales, finales e intermedios:
Cómo eliminar todos los espacios en blanco (denotado por
[:space:]
intr
):Cómo eliminar solo los espacios en blanco iniciales:
Cómo eliminar solo los espacios en blanco finales:
Cómo eliminar los espacios iniciales y finales: encadene los
sed
s:Alternativamente, si su golpe lo admite, puede reemplazar
echo -e "${FOO}" | sed ...
consed ... <<<${FOO}
, al igual que (por espacios en blanco):fuente
tr
ysed
con[[:space:]]
. Tenga en cuenta que elsed
enfoque solo funcionará en la entrada de una sola línea . Para los enfoques que funcionan con entrada de varias líneas y también usan las funciones integradas de bash, vea las respuestas de @bashfu y @GuruM. Una versión generalizada en línea de la solución de @Nicholas Sushkin se vería así:trimmed=$([[ " test test test " =~ [[:space:]]*([^[:space:]]|[^[:space:]].*[^[:space:]])[[:space:]]* ]]; echo -n "${BASH_REMATCH[1]}")
alias trim="sed -e 's/^[[:space:]]*//g' -e 's/[[:space:]]*\$//g'"
a su le~/.profile
permite usarecho $SOMEVAR | trim
ycat somefile | trim
.sed
solución que sólo se utiliza una única expresión en lugar de dos:sed -r 's/^\s*(\S+(\s+\S+)*)\s*$/\1/'
. Recorta los espacios en blanco iniciales y finales, y captura cualquier secuencia separada por espacios en blanco de caracteres que no sean espacios en blanco en el medio. ¡Disfrutar!|
fin de mantenerla como una sola expresión, en lugar de varias.Una respuesta simple es:
Xargs hará el recorte por ti. Es un comando / programa, sin parámetros, devuelve la cadena recortada, ¡así de fácil!
Nota: esto no elimina todos los espacios internos, por lo que
"foo bar"
permanece igual; NO se hace"foobar"
. Sin embargo, múltiples espacios se condensarán en espacios individuales, por lo que"foo bar"
se convertirán"foo bar"
. Además, no elimina los caracteres de final de línea.fuente
xargs echo
solo para ser detallado sobre lo que estoy haciendo, pero xargs por sí solo usará echo por defecto.sed 's/ *$//'
como alternativa. Se puede ver laxargs
nueva línea como esta:echo -n "hey thiss " | xargs | hexdump
se dará cuenta de0a73
laa
es la nueva línea. Si haces lo mismo consed
:echo -n "hey thiss " | sed 's/ *$//' | hexdump
verás0073
, no hay nueva línea.a<space><space>b
ena<space>b
. 2. Aún más: se convertiráa"b"c'd'e
enabcde
. 3. Aún más: fallaráa"b
, etc.Hay una solución que solo usa los componentes integrados de Bash llamados comodines :
Aquí está lo mismo envuelto en una función:
Pasa la cadena que se recortará en forma de comillas. p.ej:
Lo bueno de esta solución es que funcionará con cualquier shell compatible con POSIX.
Referencia
fuente
s=" 1 2 3 "; echo \""${s%1 2 3 }"\"
recortaría todo desde el final, devolviendo la delantera" "
. Subbing1 2 3
with[![:space:]]*
le dice que "busque el primer personaje no espacial, luego aplíquelo y todo lo que sigue". Usar en%%
lugar de%
hace que la operación de recorte desde el final sea codiciosa. Esto está anidado en un recorte no codicioso desde el principio, por lo que, en efecto, recorta" "
desde el principio. Luego, cambie%, # y * por los espacios finales. Bam!/bin/sh
(solo con/usr/xpg4/bin/sh
, pero esto no es lo que se usará con los scripts sh habituales).${var%%[![:space:]]*}
dice "eliminar devar
su subcadena más larga que comienza con un carácter no espacial". Eso significa que solo te quedan los espacios iniciales, que luego eliminas${var#..
. La siguiente línea (final) es lo contrario.awk
,sed
,tr
,xargs
) sólo para los espacios en blanco del ajuste de una sola cadena es fundamentalmente loco - sobre todo cuando la mayoría de las conchas (incluyendo bash) ya proporcionar cadena nativa instalaciones munging fuera de la caja.Bash tiene una característica llamada expansión de parámetros , que, entre otras cosas, permite el reemplazo de cadenas basado en los llamados patrones (los patrones se parecen a expresiones regulares, pero existen diferencias y limitaciones fundamentales). [Línea original de flussence: Bash tiene expresiones regulares, pero están bien ocultas:]
A continuación se muestra cómo eliminar todo el espacio en blanco (incluso desde el interior) de un valor variable.
fuente
${var/ /}
elimina el primer caracter de espacio.${var// /}
elimina todos los caracteres de espacio. No hay forma de recortar solo los espacios en blanco iniciales y finales con solo esta construcción.Para eliminar todos los espacios desde el principio y el final de una cadena (incluidos los caracteres de final de línea):
Esto eliminará espacios duplicados también:
Produce: 'esta cadena tiene muchos espacios'
fuente
echo -n
en absoluto?echo " my string " | xargs
Tiene la misma salida.Pele un espacio inicial y uno posterior
Por ejemplo:
Salida:
Desnuda todo los espacios iniciales y finales
Por ejemplo:
Salida:
fuente
'hello world ', 'foo bar', 'both sides '
De la sección Bash Guide sobre globbing
Para usar un extglob en una expansión de parámetros
Aquí está la misma funcionalidad envuelta en una función (NOTA: es necesario citar la cadena de entrada pasada a la función):
Uso:
Si modificamos la función para ejecutarla en un subshell, no tenemos que preocuparnos por examinar la opción de shell actual para extglob, solo podemos configurarla sin afectar el shell actual. Esto simplifica enormemente la función. También actualizo los parámetros posicionales "en su lugar" para que ni siquiera necesite una variable local
entonces:
fuente
extglob
, utilizandoshopt -p
: simplemente escribalocal restore="$(shopt -p extglob)" ; shopt -s extglob
al principio de su función yeval "$restore"
al final (excepto, concedido, eval es malo ...).[[:space:]]
podría reemplazarse con, bueno, un espacio:${var##+( )}
y${var%%+( )}
funciona bien y son más fáciles de leer.Puede recortar simplemente con
echo
:fuente
foo
contiene un comodín? por ejemplo,foo=" I * have a wild card"
... sorpresa! Además, esto colapsa varios espacios contiguos en uno.Siempre lo he hecho con sed
Si hay una solución más elegante, espero que alguien la publique.
fuente
sed
?sed -e 's/\s*$//'
. Explicación: 's' significa búsqueda, el '\ s' significa todos los espacios en blanco, el '*' significa cero o muchos, el '$' significa hasta el final de la línea y '//' significa sustituir todas las coincidencias con una cadena vacía .Puede eliminar nuevas líneas con
tr
:fuente
Con las características de coincidencia de patrones extendidos de Bash habilitadas (
shopt -s extglob
), puede usar esto:{trimmed##*( )}
para eliminar una cantidad arbitraria de espacios iniciales.
fuente
/bin/sh -o posix
funciona también pero sospecho.trimmed
? ¿Es una cosa incorporada o la variable que se está recortando?fuente
read
que almacenará en la variable por su nombre $ 1 una versión recortada de su valor $ {! 1}trim() { while [[ $# -gt 0 ]]; do read -rd '' $1 <<<"${!1}"; shift; done; }
read -rd '' str <<<"$str"
servirá.Hay muchas respuestas, pero todavía creo que vale la pena mencionar mi guión recién escrito porque:
"$*"
une múltiples argumentos usando un espacio. si desea recortar y generar solo el primer argumento, use"$1"
en su lugarLa secuencia de comandos:
Uso:
Salida:
fuente
[\ \t]
[[:space:]]
como en una de las otras respuestas: stackoverflow.com/a/3352015/3968618Puedes usar la vieja escuela
tr
. Por ejemplo, esto devuelve el número de archivos modificados en un repositorio de git, espacios en blanco despojados.fuente
Esto funcionó para mí:
Para poner eso en menos líneas para el mismo resultado:
fuente
${var##Pattern}
obtener más detalles. Además, este sitio explica los patrones de bash . Entonces, los##
medios eliminan el patrón dado de la parte delantera y los%%
medios eliminan el patrón dado de la parte posterior. La+( )
porción es el patrón y significa "una o más ocurrencias de un espacio"O
O
O
O
Sobre la base de la expritución de moskit ...
O
fuente
He visto scripts que solo usan asignación de variables para hacer el trabajo:
El espacio en blanco se fusiona y recorta automáticamente. Hay que tener cuidado con los metacaracteres de shell (riesgo potencial de inyección).
También recomendaría siempre las sustituciones variables de comillas dobles en condicionales de shell:
ya que algo como un -o u otro contenido en la variable podría modificar sus argumentos de prueba.
fuente
$xyz
with loecho
que hace la fusión de espacios en blanco, no la asignación de variables. Para almacenar el valor recortado en la variable en su ejemplo, tendría que usarxyz=$(echo -n $xyz)
. Además, este enfoque está sujeto a la expansión de nombre de ruta potencialmente no deseada (globbing).xyz
variable NO se recorta.fuente
echo $(echo "1 2 3")
(con dos espacios entre 1, 2 y 3).Simplemente usaría sed:
a) Ejemplo de uso en cadena de una sola línea
Salida:
b) Ejemplo de uso en cadenas de líneas múltiples
Salida:
c) Nota final:
si no le gusta usar una función, para una cadena de una sola línea puede simplemente usar un comando "más fácil de recordar" como:
Ejemplo:
Salida:
Usar lo anterior en cadenas de varias líneas también funcionará , pero tenga en cuenta que también cortará cualquier espacio múltiple interno posterior / principal, como GuruM notó en los comentarios
Salida:
Entonces, si le importa mantener esos espacios, ¡use la función al comienzo de mi respuesta!
d) EXPLICACIÓN de la sintaxis sed "buscar y reemplazar" en cadenas de líneas múltiples utilizadas dentro de la función trim:
fuente
Aquí hay una función trim () que recorta y normaliza los espacios en blanco
Y otra variante que usa expresiones regulares.
fuente
*
carácter en la cadena de entrada expandirse a todos los archivos y carpetas en la carpeta de trabajo actual. Finalmente, si $ IFS se establece en un valor no predeterminado, el recorte puede no funcionar (aunque eso se soluciona fácilmente agregandolocal IFS=$' \t\n'
). El recorte se limita a las siguientes formas de espacios en blanco: espacios\t
y\n
caracteres.if
línea con:if [[ "$trimmed" =~ ' '*([^ ]|[^ ].*[^ ])' '* ]]
. Finalmente, el enfoque solo trata con espacios, no con otras formas de espacios en blanco (ver mi próximo comentario).if
línea con:[[ "$trimmed" =~ [[:space:]]*([^[:space:]]|[^[:space:]].*[^[:space:]])[[:space:]]* ]]
Use AWK:
fuente
$stripped_version=
echo $ var | awk '{gsub (/ ^ + | + $ /, "")} 1''`Las asignaciones ignoran los espacios en blanco iniciales y finales y, como tales, se pueden usar para recortar:
fuente
echo "$var"
para ver el valor con espacios.var=$(echo $var)
pero no lo recomiendo. Se prefieren otras soluciones presentadas aquí.Esto no tiene el problema con el globbing no deseado, también, el espacio en blanco interior no se modifica (suponiendo que
$IFS
esté establecido en el valor predeterminado, que es' \t\n'
).Se lee hasta la primera línea nueva (y no la incluye) o el final de la cadena, lo que ocurra primero, y elimina cualquier combinación de
\t
caracteres y espacios iniciales y finales . Si desea conservar varias líneas (y también eliminar las nuevas líneas iniciales y finales), useread -r -d '' var << eof
en su lugar; tenga en cuenta, sin embargo, que si su entrada contiene\neof
, se cortará justo antes. (Otras formas de espacio en blanco, es decir\r
,\f
y\v
, se no despojado, incluso si se agregan a $ IFS).fuente
Para eliminar espacios y pestañas de izquierda a primera palabra, ingrese:
cyberciti.biz/tips/delete-leading-spaces-from-front-of-each-word.html
fuente
Esto eliminará todos los espacios en blanco de su cadena,
/
reemplaza la primera aparición y//
todas las ocurrencias de espacios en blanco en la cadena. Es decir, todos los espacios en blanco se reemplazan por nadafuente
Este es el método más simple que he visto. Solo usa Bash, solo unas pocas líneas, la expresión regular es simple y coincide con todas las formas de espacios en blanco:
Aquí hay un script de muestra para probarlo:
fuente
^[[:space:]]*(.*[^[:space:]])?[[:space:]]*$
Python tiene una función
strip()
que funciona de manera idéntica a la de PHPtrim()
, por lo que podemos hacer un poco de Python en línea para hacer una utilidad fácilmente comprensible para esto:Esto recortará los espacios en blanco iniciales y finales (incluidas las nuevas líneas).
fuente
fuente
Descubrí que necesitaba agregar algo de código de una
sdiff
salida desordenada para limpiarlo:Esto elimina los espacios finales y otros caracteres invisibles.
fuente
Eliminar espacios en un espacio:
fuente