Rimozione di tutti i caratteri non ASCII da un flusso di lavoro (file)


13

Come rimuoverei tutti i caratteri non ASCII da un file? Ci sarebbe un comando specifico per eseguire questo?

grep --colour='auto' -P -n'[^\x00-\x7]' /usr/local/...

Credo che questo trovi i personaggi all'interno del flusso di lavoro, ma come rimuoverei tutte le istanze dei personaggi in questione?



2
correlati: se vuoi solo evitare problemi con i caratteri di controllo (invece di eliminarli silenziosamente), puoi semplicemente usarli cat -vper mostrarli nella rappresentazione ASCII per loro. (es. ^Gper \007)
Matija Nalis,

1
Quando dici "caratteri non ascii" includi anche caratteri accentati?
Captain Man,

1
@MatijaNalis Ulteriori informazioni sulla rappresentazione: en.wikipedia.org/wiki/Caret_notation
wjandrea

1
Qual è il caso d'uso? Molto spesso ci sono strumenti specifici o approcci diversi che funzionano molto meglio della semplice rimozione di un gruppo di caratteri speciali. Nota che ASCII include diversi caratteri "speciali" come schede verticali, campana e NUL: sei sicuro di non voler dire caratteri stampabili ?
l0b0

Risposte:


26

I caratteri ASCII sono caratteri compresi nell'intervallo da 0 a 177 (ottale) .

Per eliminare caratteri al di fuori di questo intervallo in un file, utilizzare

LC_ALL=C tr -dc '\0-\177' <file >newfile

Il trcomando è un'utilità che funziona su singoli caratteri , sostituendoli con altri caratteri singoli (traslitterazione), eliminandoli o comprimendo le esecuzioni dello stesso carattere in un singolo carattere.

Il comando sopra dovrebbe leggere filee scrivere il contenuto modificato in newfile. L' -dopzione per trfare in modo che l'utilità elimini i caratteri (invece di trasletterli), e li -cfa considerare caratteri al di fuori dell'intervallo dato (invece che all'interno).

LC_ALL=Csi assicura che ogni valore di byte costituisca un carattere valido. Senza di essa, alcune trimplementazioni si interrompono se trovassero sequenze di byte che non formano caratteri validi nella codifica dei caratteri della locale.


Per sostituire il file originale con quello modificato, utilizzare

LC_ALL=C tr -dc '\0-\177' <file >newfile &&
mv newfile file

Ciò rinomina il nuovo file con il nome del vecchio file dopo che trè stato completato correttamente. Se trnon viene completato correttamente, sia perché non è stato possibile leggere il file originale o non è possibile scrivere nel nuovo file, il file originale verrà lasciato invariato.

In alternativa, per conservare il più possibile i metadati (permessi, ecc.) Del file originale, utilizzare

cp file tmpfile &&
LC_ALL=C tr -dc '\0-\177' <tmpfile >file &&
rm tmpfile


9

Se tutto ciò di cui hai bisogno è una regex: [\x00-\x7F]che potresti applicare a diverse utility:

<file LC_ALL=C   sed   's/[^\o0-\o177]//g'      # GNU sed without POSIXLY_CORRECT
<file LC_ALL=C   awk   '{gsub(/[^\0-\177]/,"");print}'
<file            perl  -pe 's/[^[:ascii:]]//g;'
<file LC_ALL=C   tr    -dc '\0-\177'

Comprendi che sed, awk e perl si aspettano "file di testo" come definiti in Unix. Tutto funziona bene in questo caso. Ma in particolare, awk aggiunge una nuova riga finale (che esistesse o meno nel file di origine) (l'uso di printf rimuove TUTTE le nuove righe sull'input). Il tr è progettato per funzionare con qualsiasi tipo di file. Tuttavia NUL ( \0) non è un carattere valido in un file di testo POSIX e dovrebbe essere evitato:

Le righe non contengono caratteri NUL ...

In effetti, molti personaggi di controllo genererebbero altri problemi in alcune condizioni specifiche.
Quindi, probabilmente hai bisogno[\x07-\x0d\x20-\x7e]

<file LC_ALL=C   sed   's/[^\o007-\o015\o040-\o176]//g'            # GNU sed without POSIXLY_CORRECT
<file LC_ALL=C   awk   '{gsub(/[^\0-\15\40-\176]/,"");print}'
<file            perl  -pe 's/[^\x{7}-\x{d}\x{20}-\x{7e}]//g;'
<file LC_ALL=C   tr    -dc '\7-\15\40-\176'

L'intervallo 7-13 (in decimale) è \a\b\t\n\v\f\r(in ordine).
Un intervallo simile (probabilmente più portatile) potrebbe essere scritto come [^[:space:][:print:]] (similar because it doesn't include\ a \ b` --bell e backspace--).

<file LC_ALL=C   sed   's/[^[:space:][:print:]]//g'  # GNU sed without POSIXLY_CORRECT
<file LC_ALL=C   awk   '{gsub(/[^[:space:][:print:]]/,"");print}'
<file            perl   -pe 's/[^[:space:][:print:]]//g;'
<file LC_ALL=C   tr     -dc '[:space:][:print:]'

Correlati:
Regex qualsiasi
soluzione ASCII carattere Perl
Posix File di testo


Si noti che l'input per trpuò essere qualsiasi tipo di file, non solo file di testo. awkd'altra parte, prende un file di testo.
Kusalananda

È abbastanza difficile per me trovare qualcos'altro per chiamare un file "solo caratteri ASCII" tutt'altro che un "file di testo" (sì, sì: in parole povere). @Kusalananda (nota comunque su awk).
NotAnUnixNazi

Nota che gensub()è un'estensione gawk. Vorresti gsub(...); print, e usare le ottali invece delle sequenze esadecimali (e LC_ALL = C) per essere (più) portabili.
Stéphane Chazelas,

@ StéphaneChazelas Qual è la limitazione di GNU sed che rende specifica la sintassi GNU (capisco il problema POSIXLY_CORRECT).
NotAnUnixNazi

[^\o0]è far corrispondere caratteri diversi da barra rovesciata, o e 0 in POSIX sed(in tutte le implementazioni tranne GNU sed). Questa non è una limitazione di GNU sedma un'estensione non conforme, motivo per cui è disabilitata quando POSIXLY_CORRECT è nell'ambiente).
Stéphane Chazelas,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.