Convertir pestañas a espacios en muchos archivos


11

Tengo muchos archivos con pestañas esparcidas por todas partes, y me gustaría convertirlos a todos en espacios. Conozco el expandcomando, pero desafortunadamente tendría que escribir cada archivo que lo use. ¿Hay alguna manera más fácil de hacer esto en Linux?

Respuestas:


12

Intenta lo siguiente:

find ./ -type f -exec sed -i 's/\t/ /g' {} \;

Si quieres cuatro espacios, prueba:

find ./ -type f -exec sed -i 's/\t/    /g' {} \;

Eso reemplazará cada pestaña por un solo espacio. Como la persona mencionó el uso expand, supongo que quiere preservar la alineación del texto.
garyjohn

Debe 's/\t/ /g'reemplazar más de una pestaña por línea.
Daniel Andersson

1
Una aceleración sustancial si hay muchos archivos está haciendo " find ./ -type f -exec sed -i ’s/\t/ /g’ {} +" (es decir, " +" en lugar de " \;"), si la findversión lo admite (y personalmente no he conocido ninguna versión que no lo haga, pero no es un estándar POSIX , así que supongo que podría suceder en algunos sistemas. Consulte " -exec command {} +" en el manual). En lugar de lanzar una instancia sedpara cada archivo, esto generará una lista de argumentos con tantos argumentos de nombre de archivo como el sistema admite ( getconf ARG_MAX= 2097152 en mi sistema), al igual que xargs, y así lanzará muchos menos sedprocesos.
Daniel Andersson

66
Nota para cualquier usuario de Mac que encuentre esto: la versión de OS X de sedno comprende la \tsecuencia de escape de la pestaña. Puede reemplazarlo con un carácter de tabulación literal, que puede ingresar en el shell por [Ctrl]+V, [Tab].
Jeremy Banks

expandes probablemente mejor que sedpara esto, como se explica en: stackoverflow.com/a/11094620/131824
David Weinraub el

6

Hay muchas formas de hacer esto. También hay muchas maneras de dispararte en el pie mientras haces esto si no tienes cuidado o si eres nuevo en Linux como parece ser. Suponiendo que puede crear una lista de archivos que desea convertir, ya sea mediante el uso de algo como findo manualmente con un editor, simplemente canalice esa lista en lo siguiente.

while read file
do
   expand "$file" > /tmp/expandtmp
   mv /tmp/expandtmp "$file"
done

Una forma en la que puedes dispararte en el pie con eso es hacer un error tipográfico para que termines moviendo un archivo vacío a todos los nombres de archivo que especifiques, eliminando así el contenido de todos tus archivos. Así que tenga cuidado y pruebe lo que haga primero en un pequeño conjunto de archivos de los que ha hecho una copia de seguridad.


3
Hacer que la mvcondición de que el éxito de expand:expand ... && mv ...
En pausa hasta nuevo aviso.

No olvide expand -t 4expandir las pestañas a 4 espacios. Además, este método puede crear nuevas líneas finales. Pero de lo contrario funciona.
mgold

3
find . -type f -iname "*.js" -print0 | xargs -0 -I foo tab2space foo foo

-I foo crea una plantilla variable foo para cada línea de entrada, para que pueda consultar la entrada más de una vez.

-print0y -0diga a ambos comandos que usen \ 0 como separador de línea en lugar de ESPACIO, por lo que este comando funciona para rutas con espacios.


1
find -name \*.js -exec bash -c 'expand -t 4 "$0" | tee "$0"' {} \;

Contras: los
archivos más grandes que el tamaño del búfer de tubería ( 64 KB ) se truncan

Pros:
no
se truncan los archivos de archivos temporales más grandes que el tamaño del búfer de tubería


0

Esto es mejor:

find . -name *.java ! -type d -exec bash -c 'expand -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;

3
¿Por qué es esto mejor? No es una buena idea usarlo /tmp/eporque si algo más está usando ese archivo, esto lo estropeará. Como si dos usuarios quisieran usar esto al mismo tiempo.
Kevin Panko

0

Le di una oportunidad a este problema con los siguientes requisitos en mente:

  • Filtre los archivos según sus nombres, para procesar, por ejemplo, solo archivos .cpp o .json
  • Soporta procesamiento paralelo. En caso de que haya muchos archivos, esto puede proporcionar una gran velocidad
  • La solución debe caber en una línea para facilitar su uso.

El último requisito fue el más difícil de cumplir porque "expandir" no permite modificar los archivos en su lugar.

Se me ocurrió la siguiente solución:

find . -type f -regextype egrep -regex '.*\.(c|cpp|h|hpp)'  -print0 | xargs -0 -n 1 -P 10 -IFILE bash -c ' ( echo "Processing FILE..." && expand -t 4 "FILE" > /tmp/expand.$$ && mv /tmp/expand.$$ "FILE" ) || exit 255'

Aquí hay alguna explicación:

  • "find" busca los archivos para procesar. "-regextype egrep" permite filtrarlos según su nombre y una expresión regular en el formato "egrep"
  • el parámetro "-type f" asegura que solo coincidiremos con los archivos normales, no por ejemplo directorios o cualquier otra cosa especial
  • el parámetro "-regexp" es la expresión regular en sí misma, que coincide en este caso con cualquier archivo que termine con .c, .cpp, .h o .hpp (el nombre completo debe coincidir, por lo que "file.c2" no , que es lo que queremos)
  • "-print0" indica a "find" que imprima las rutas del archivo en su salida estándar con el carácter 0 al final de cada ruta. Junto con la opción "-0" para "xargs", permite pasar nombres que contienen carros de retorno de una herramienta a otra (incluso si es una situación bastante rara ...)
  • xargs inicia un nuevo proceso para cada ruta ("-n 1"), pero puede ejecutar hasta 10 procesos en paralelo ("-P 10")
  • xargs usa el alias "ARCHIVO" para pasar cada ruta de archivo al comando, que es un script bash
  • la secuencia de comandos bash llama "expandir" y guarda el resultado en un archivo temporal cuyos nombres contienen el ID del proceso actual ($$), de modo que todos los procesos que se ejecutan en paralelo en un archivo determinado utilizan archivos temporales diferentes
  • todo el comando usa el patrón (comando1 && comando2 && comando3) para que el proceso se detenga si algún subcomando devuelve un error
  • si hay algún error de la cadena "&&" anterior, el script bash devolverá un código de salida 255 que hará que xargs se detenga inmediatamente
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.