¿Cómo escapar de caracteres especiales en una cadena?

16

Suponiendo que $filetiene un valor de un nombre de archivo, por ejemplo Dr' A.tif. En la programación de bash, ¿cómo podría escapar de la comilla simple y de cualquier otro carácter especial $filesin eliminar el carácter especial?

Actualización el 9 de julio de 2014

Como solicitud de @Gilles , siguiendo el fragmento de código que no puede manejar Dr' A.tif:

files=$(find /path/ -maxdepth 1 -name "*.[Pp][Dd][Ff]" -o -name "*.[Tt][Ii][Ff]")
echo "${files}" > ${TEMP_FILE}
while read file
do
   newfile=$(echo "${file}" | sed 's, ,\\ ,g') ## line 1
done < ${TEMP_FILE}

Después he probado la respuesta de @Patrick en line 1, parece que funciona para mí. Pero si tengo un archivo como Dr\^s A.tif, el printfcomando no parece ayudar, me lo muestra Dr\^s\ A.tif. Si lo pruebo manualmente en la consola de esta manera:

printf "%q" "Dr\^s A.tif"

Tendré esta salida:

Dr\\\^s\ A.tif

¿Alguna idea de cómo manejar esto?

huahsin68
fuente
3
¿en qué contexto espera usar $ file? ¿o este problema asigna la cadena con el carácter especial a $ file?
robar el
En realidad, el comando find me devuelve una matriz de lista de archivos. Y luego recorro esta lista de archivos en $ file variable.
huahsin68
2
Aquí se le han dado algunas respuestas correctas, pero probablemente no sean las respuestas a la pregunta que realmente está haciendo. Por su comentario aquí, sospecho que está en el camino equivocado. No podemos ayudarlo mucho porque sigue sin mostrar su código. Sin embargo, le recomiendo que lea ¿Por qué mi script de shell se ahoga en espacios en blanco u otros caracteres especiales? como fondo Muestre su guión y explique lo que quiere hacer.
Gilles 'SO- deja de ser malvado'

Respuestas:

14

Puede usar el printfbuiltin con %qpara lograr esto. Por ejemplo:

$ file="Dr' A.tif"
$ printf '%q\n' "$file"
Dr\'\ A.tif

$ file=' foo$bar\baz`'
$ printf '%q\n' "$file"
\ foo\$bar\\baz\`

De la documentación de bash en printf:

In addition to the standard format specifications described in printf(1)
and printf(3), printf interprets:

 %b       expand backslash escape sequences in the corresponding argument
 %q       quote the argument in a way that can be reused as shell input
 %(fmt)T  output the date-time string resulting from using FMT as a format
          string for strftime(3)
Patricio
fuente
Esto no funciona con ciertos casos .eg cuando necesita conservar comillas dobles.
user3467349
@ user3467349 funciona bien con comillas. Apuesto a que estás intentando algo así printf '%s' "foo". Primero debe comprender cómo funciona el análisis de argumentos en el shell. Consulte gnu.org/software/bash/manual/bash.html#Shell-Operation # 2 ocurre antes del # 6.
Patrick
¿Podría proporcionar un ejemplo de esta cadena impresa con printfy sin otras manipulacionesIt doesn't have a: ""
User3467349
Su problema no tiene nada que ver con printf. Su problema es que no desea que el shell analice su cadena. Para hacer eso, debe pasar su entrada al shell de manera que ni siquiera intente analizarlo. Una forma de hacerlo sería read -r -p 'input: ' && printf '%q\n' "$REPLY"y proporcionar la entrada cuando se le solicite.
Patrick
1
Como he dicho varias veces ahora. No saber cómo pasar datos sin procesar al shell no es un problema printf. Quizás debería hacer una pregunta en lugar de criticar una solución que no tiene nada que ver con su problema.
Patrick
4

Tratar:-

file=Dr\'\ A.tif
echo $file
Dr' A.tif

o

file="Dr' A.tif"
echo $file
Dr' A.tif

o si la cadena contiene una comilla doble: -

file='Dr" A.tif'
echo $file
Dr" A.tif

Hay buenos tutoriales sobre cómo escapar y citar en la red. Comience con este .

garethTheRed
fuente
1

No necesita escapar de ningún nombre de archivo que esté manejando en un script. Escapar solo es necesario si desea poner un nombre de archivo como literal en una secuencia de comandos, o pasar varios nombres de archivo como una secuencia de entrada única a otra secuencia de comandos.

Dado que está recorriendo la salida de find, esta es una de las formas más simples (!) De manejar todas las rutas posibles :

while IFS= read -r -d ''
do
    file_namex="$(basename -- "$REPLY"; echo x)"
    file_name="${file_namex%$'\nx'}"
    do_something -- "$file_name"
done <(find "$some_path" -exec printf '%s\0' {} +)
l0b0
fuente
0

rápido y (muy) sucio

find . | sed 's/^/"/' | sed 's/$/"/'
Miguel
fuente
-1

Muchas de estas respuestas, incluida la más votada printf "%q", no funcionarán en todos los casos sin una manipulación adicional. Sugeriría lo siguiente (ejemplo a continuación):

cat <<EOF; 2015-11-07T03:34:41Z app[postgres.0000]: [TAG] text-search query doesn't contain lexemes: "" EOF

usuario3467349
fuente
Disculpe la pregunta n00b, pero ¿puede explicar cómo usaría esto para escapar de los caracteres en una cadena? Si copio el código que escribe en mi terminal, solo imprime 2015-11-07T03: 34: 41Z aplicación [postgres.0000]: [TAG] la consulta de búsqueda de texto no contiene lexemas: "" ... no se escapa nada .
SharkAlley
Ese es literalmente el punto, todos los caracteres especiales se interpretan como caracteres literales, no por su significado especial. Intente hacer eco de "la cadena anterior" para ver la diferencia.
user3467349