elimine los espacios finales de los archivos de texto SÓLO cuando sea necesario

elimine los espacios finales de los archivos de texto SÓLO cuando sea necesario

Estoy eliminando los espacios finales usando

sed -i 's/[ \t]*$//' *.txt

Sin embargo, este comando reescribirá todos los archivos.

¿Existe una manera conveniente de juzgar si hay espacios finales en un archivo de texto y omitir los que no tienen espacios finales?

Respuesta1

Podrías usar grepfirst para encontrar si hay líneas que necesitan modificarse, aunque eso aún leería los archivos dos veces en el peor de los casos (en el caso de que solo sea necesario modificar la última línea):

for f in ./*.txt; do
    grep -q '[[:blank:]]$' "$f" &&
      sed -i 's/[[:blank:]]*$//' "$f"
done

Respuesta2

Una forma puede ser find/grep/sedcomo se muestra:

find . -maxdepth 1 -type f -name '*.txt' \
  -exec grep -q '[[:blank:]]$' {} \; \
  -exec sed -Ei -e 's/[[:blank:]]+$//' {} +
  • la búsqueda con -max Depth si 1 opera dentro del directorio actual.
  • {} \; se refiere al nombre del archivo que se pasa grepy \;escapa del punto y coma del metacarácter del shell, que es un indicador de fin de comando. Lo escapamos para que llegue -exec. Alternativamente, podrías haberlo escrito como';'
  • {} + ya lo sabe {}ahora y eso +significa que debe pasar tantos nombres de archivos como sea posible sed(básicamente, en lugar de pasar el único {}del findresultado actual, acumule una lista {}para usar como argumento antes de llamar sed). Esto nos permite minimizar el número de sedinvocaciones.

Respuesta3

Realice la edición y sólo sustituya el archivo original si hay una diferencia.

for file in *.txt
do
    sed 's/[ \t]*$//' < "$file" > "$file.tmp.$$" || continue
    cmp -s -- "$file" "$file.tmp.$$" ||
      cat < "$file.tmp.$$" > "$file" ||
      continue
    rm -f -- "$file.tmp.$$"
done

Respuesta4

Lo siguiente se basa enla idea de roaimade ejecutar la sedexpresión en todos los archivos, pero luego solo conservar los archivos que realmente se modificaron.

Lo modifica haciendo menos sedinvocaciones:

printf '%s\0' ./*.txt |
xargs -0 sed -i.bak 's/[[:blank:]]$//

Luego podrá revisar los *.txtarchivos, compararlos con los originales y elegir el que desea conservar:

for name in ./*.txt; do
    if cmp -s "$name" "$name.bak"; then
        # keep original
        mv "$name.bak" "$name"
    else
        # keep modified
        rm "$name.bak"
    fi
done

O hacer ambas cosas a la vez:

printf '%s\0' ./*.txt |
xargs -0 sh -c '
    sed -i.bak "s/[[:blank:]]$//" "$@"
    for name do
        if cmp -s "$name" "$name.bak"; then
            mv "$name.bak" "$name"
        else
            rm "$name.bak"
        fi
    done' sh

información relacionada