sed com quantificadores numéricos - como fazer?
Estou tentando editar cabeçalhos fasta de vários arquivos, a fim de remover uma barra e tudo o que vem depois dela (contanto que 'tudo que vem depois' seja igual ou menor que 10 caracteres). As linhas de cabeçalho são marcadas por '>'.
for i in ./*.fa;do sed -r 's/(>.*)\/.\{,10\}\n/\1\n/' "$i"; done
Eu também tentei
for i in ./*.fa;do sed -r 's/(>.*)\/.{,10}\n/\1\n/' "$i"; done
mas não parece ser melhor. Meu palpite é que é o quantificador {, 10} que quebra as coisas. Eu não tenho certeza embora. Ajuda seria muito apreciada!
Por exemplo, se o seguinte estiver em um arquivo:
>header1_some_extra_data_here/1-1000
ATGCGGGTACCCCA
>code/header2_some_extra_data
AGGTCCCCGGGAAAAA
Eu gostaria que o seguinte fosse a saída:
>header1_some_extra_data_here
ATGCGGGTACCCCA
>code/header2_some_extra_data
AGGTCCCCGGGAAAAA
Respostas
Suas sedsubstituições não funcionarão conforme o esperado porque você nunca será capaz de corresponder a uma nova linha nos dados de entrada. Isso ocorre porque sedlê seu arquivo linha por linha, ou seja, com as novas linhas como delimitadores, e as expressões são aplicadas às linhas individualmente, sem as novas linhas delimitadoras.
Em vez disso, alterando ligeiramente o seu código:
for fasta in ./*.fa; do
sed 's;^\(>.*\)/.\{0,10\}$;\1;' "$fasta"
done
As poucas mudanças que fiz são:
- Use
;como delimitador para os///comando em vez do padrão/. Isso nos permite não escapar/do padrão. Quase qualquer caractere pode ser usado como delimitador, mas provavelmente deve-se escolher um que não ocorra no padrão ou no texto de substituição. - Use apenas a sintaxe de expressão regular básica padrão. Em seu padrão,
(...)é a sintaxe de expressão regular estendida e\{...\}é a sintaxe de expressão regular básica. Decidi usar a sintaxe básica para portabilidade. Isso também significa descartar a-ropção que ativa a sintaxe estendida no GNUsed. - Ancorar o padrão no início e no final da linha com
^e$respectivamente. - Não tente inserir uma nova linha no bit de substituição.
Uma sedexpressão alternativa e mais curta seria
sed '/^>/s;/.\{0,10\}$;;'
Isso aplica uma substituição a todas as linhas que começam com o >caractere ( /^>/atua como o "endereço" para o s///comando subsequente ). A substituição simplesmente exclui o /e o bit após ele no final da linha se esse bit tiver 10 caracteres ou menos.
Esta é uma maneira ligeiramente diferente:
Salve a saída em novos arquivos:
for file in *fa; do sed -E 's|^\s*(>.{10,}.*)/.*|\1|' "$file" > "$file.fixed"; doneEdite os arquivos no local:
sed -i -E 's|^\s*(>.{10,}.*)/.*|\1|' *.fa
A -Eopção ativa expressões regulares estendidas. Isso nos permite usar ()para captura e {}para repetições sem a necessidade de escapar delas. Eu também alterei o delimitador para |para maior clareza e adicionei ^\s*(observe que isso pode não ser compatível com o seu sed; se não for, você pode usar no ^ *lugar), já que às vezes você pode ter um espaço >em branco antes dos arquivos fasta.
Então, o truque é combinar a >seguido por 10 ou mais caracteres até a /, capturar esses caracteres com os parênteses para que eles se tornem \1e substitua a linha inteira com apenas a parte combinada.
Observe que isso encontrará o trecho mais longo de> 10 caracteres até o último /. Portanto, se houver vários /na mesma linha, todos serão mantidos, exceto o último. Por exemplo:
$ 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
Para evitar isso e remover tudo após o primeiro /, desde que você já tenha correspondido 10 caracteres, use:
sed -E 's|^\s*(>.{10}[^/]*)/.*|\1|'