remova espaços finais de arquivos de texto SOMENTE quando necessário

remova espaços finais de arquivos de texto SOMENTE quando necessário

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 grepfirst 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/sedcomo 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 passado grepe \;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ível sed(basicamente, em vez de passar o único {}do findresultado atual, acumule uma lista de {}para serem usados ​​​​como argumento antes de chamar sed). Isso nos permite minimizar o número de sedinvocaçõ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 sedexpressão em todos os arquivos, mas mantendo apenas os arquivos que foram realmente modificados.

Ele modifica isso fazendo menos sedinvocações:

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

Você pode então percorrer os *.txtarquivos, 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

informação relacionada