sed con quantificatori numerici - come fare?
Sto cercando di modificare le intestazioni fasta di più file, al fine di rimuovere una barra e tutto ciò che segue (purché 'tutto dopo' sia uguale o inferiore a 10 caratteri). Le righe di intestazione sono contrassegnate da un ">".
for i in ./*.fa;do sed -r 's/(>.*)\/.\{,10\}\n/\1\n/' "$i"; done
Ho anche provato
for i in ./*.fa;do sed -r 's/(>.*)\/.{,10}\n/\1\n/' "$i"; done
ma non sembra essere migliore. La mia impressione è che sia il quantificatore {, 10} che rompe le cose. Non sono sicuro però. L'aiuto sarebbe molto apprezzato!
Ad esempio, se il seguente era in un file:
>header1_some_extra_data_here/1-1000
ATGCGGGTACCCCA
>code/header2_some_extra_data
AGGTCCCCGGGAAAAA
Vorrei che l'output fosse il seguente:
>header1_some_extra_data_here
ATGCGGGTACCCCA
>code/header2_some_extra_data
AGGTCCCCGGGAAAAA
Risposte
Le tue sedsostituzioni non funzioneranno come previsto perché non sarai mai in grado di abbinare una nuova riga nei dati di input. Questo perché sedlegge il tuo file riga per riga, cioè con i caratteri di ritorno a capo come delimitatori, e le espressioni vengono applicate alle righe individualmente, senza i caratteri di delimitazione.
Invece, cambiando leggermente il codice:
for fasta in ./*.fa; do
sed 's;^\(>.*\)/.\{0,10\}$;\1;' "$fasta"
done
Le poche modifiche che ho fatto sono:
- Utilizzare
;come delimitatore per ils///comando invece di quello predefinito/. Questo ci permette di non sfuggire/allo schema. Quasi tutti i caratteri possono essere usati come delimitatori, ma probabilmente si dovrebbe sceglierne uno che non si trova nel modello o nel testo sostitutivo. - Utilizzare solo la sintassi delle espressioni regolari di base standard. Nel tuo modello,
(...)è la sintassi delle espressioni regolari estesa ed\{...\}è la sintassi delle espressioni regolari di base. Ho deciso di utilizzare la sintassi di base per la portabilità. Ciò significa anche eliminare l'-ropzione che abilita la sintassi estesa in GNUsed. - Ancorare il motivo all'inizio e alla fine della linea rispettivamente con
^e$. - Non provare a inserire una nuova riga nel bit di sostituzione.
Un'espressione alternativa e più breve sedsarebbe
sed '/^>/s;/.\{0,10\}$;;'
Questo applica una sostituzione a tutte le righe che iniziano con il >carattere ( /^>/funge da "indirizzo" per il s///comando successivo ). La sostituzione cancella semplicemente il /e il bit dopo di esso alla fine della riga se quel bit è lungo 10 caratteri o meno.
Ecco un modo leggermente diverso:
Salva l'output in nuovi file:
for file in *fa; do sed -E 's|^\s*(>.{10,}.*)/.*|\1|' "$file" > "$file.fixed"; doneModifica i file sul posto:
sed -i -E 's|^\s*(>.{10,}.*)/.*|\1|' *.fa
L' -Eopzione abilita le espressioni regolari estese. Questo ci consente di utilizzare ()per la cattura e {}per le ripetizioni senza bisogno di sfuggirle. Ho anche cambiato il delimitatore in |per chiarezza e aggiunto ^\s*(nota che questo potrebbe non essere supportato dal tuo sed; se non lo è, puoi usarlo ^ *invece) poiché a volte puoi avere spazi bianchi prima dei >file in fasta.
Quindi, il trucco è abbinare a >seguito da 10 o più caratteri fino a /, catturare questi caratteri con le parentesi in modo che diventino \1e sostituire l'intera riga con solo la parte abbinata.
Nota che questo troverà il tratto più lungo di> 10 caratteri fino all'ultimo /. Quindi, se ce ne sono più /sulla stessa riga, verranno mantenuti tutti tranne l'ultimo. Per esempio:
$ echo ">header1_some_extra_data_here/1-1000/foo/bar/baz" |
sed -E 's|^\s*(>.{10,}.*)/.*|\1|'
>header1_some_extra_data_here/1-1000/foo/bar
Per evitarlo e rimuovere tutto dopo il primo /purché abbiate già trovato 10 caratteri, usate:
sed -E 's|^\s*(>.{10}[^/]*)/.*|\1|'