Estou removendo os espaços finais usando
sed -i 's/[ \t]*$//' *.txt
No entanto, este comando irá reescrever todos os arquivos.
Existe uma maneira conveniente de julgar se há espaços à direita em um arquivo de texto e ignorar aqueles sem espaços à direita?
Responder1
Você poderia usar grep
first para descobrir se há linhas que precisam ser modificadas, embora isso ainda leia os arquivos duas vezes, na pior das hipóteses (no caso em que apenas a última linha precise ser modificada):
for f in ./*.txt; do
grep -q '[[:blank:]]$' "$f" &&
sed -i 's/[[:blank:]]*$//' "$f"
done
Responder2
Uma maneira pode ser find/grep/sed
como mostrado:
find . -maxdepth 1 -type f -name '*.txt' \
-exec grep -q '[[:blank:]]$' {} \; \
-exec sed -Ei -e 's/[[:blank:]]+$//' {} +
- a localização com -maxprofundidade se 1 operar no diretório atual.
{} \;
está se referindo ao nome do arquivo que está sendo passadogrep
e\;
está escapando do ponto e vírgula do metacaractere do shell, que é um indicador de fim de comando. Nós escapamos para que ele alcance-exec
. Você poderia alternativamente ter escrito como';'
{} +
você já sabe{}
agora e isso+
significa passar tantos nomes de arquivos quanto possívelsed
(basicamente, em vez de passar o único{}
dofind
resultado atual, acumule uma lista de{}
para serem usados como argumento antes de chamarsed
). Isso nos permite minimizar o número desed
invocações.
Responder3
Faça a edição e só substitua o arquivo original se houver diferença.
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
Responder4
O seguinte se baseiaideia de Roaimade executar a sed
expressão em todos os arquivos, mas mantendo apenas os arquivos que foram realmente modificados.
Ele modifica isso fazendo menos sed
invocações:
printf '%s\0' ./*.txt |
xargs -0 sed -i.bak 's/[[:blank:]]$//
Você pode então percorrer os *.txt
arquivos, comparando-os com os originais e escolhendo aquele que deseja manter:
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
Ou, fazendo as duas coisas de uma só 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