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 grep
first 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/sed
como 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 pasagrep
y\;
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 posiblesed
(básicamente, en lugar de pasar el único{}
delfind
resultado actual, acumule una lista{}
para usar como argumento antes de llamarsed
). Esto nos permite minimizar el número desed
invocaciones.
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 sed
expresión en todos los archivos, pero luego solo conservar los archivos que realmente se modificaron.
Lo modifica haciendo menos sed
invocaciones:
printf '%s\0' ./*.txt |
xargs -0 sed -i.bak 's/[[:blank:]]$//
Luego podrá revisar los *.txt
archivos, 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