removendo o primeiro e o último caractere de cada linha da linha de comando

8

Estou tentando remover o primeiro e o último caracteres de todas as linhas em um arquivo de texto e salvar a versão truncada resultante em um novo arquivo. Alguém tem uma idéia sobre como fazer isso de forma eficiente usando awkou outros programas / comandos linux especificamente para arquivos grandes?

input.txt

(s,2,4,5,6)
"s,1,5,5,2"
{z,0,4,5,3}
[y,2,4,5,5]
(y,4,4,5,7)
(r,20,4,5,7)
(e,9,4,5,2)

Output.txt esperado

s,2,4,5,6
s,1,5,5,2
z,0,4,5,3
y,2,4,5,5
y,4,4,5,79
r,20,4,5,7
e,9,4,5,2
pacodelumberg
fonte

Respostas:

14

Outra maneira apenas para o diabo:

rev input | cut -c2- | rev | cut -c2-

(Nota: com o GNU cut, ele funciona apenas para caracteres feitos de apenas um byte (como no seu exemplo)).

Drake Clarris
fonte
Agradável! Isso é significativamente mais rápido que as soluções sed e awk propostas até agora.
Gilles 'SO- stop be evil'
Eu propus esta resposta para pessoas com medo da sintaxe sed / awk / regex, mas não imaginariam que fosse mais rápida, especialmente para arquivos grandes, com três pipes e passando todo o conteúdo por cada um. Teria pensado que sed ou awk, lendo uma linha por vez, seria mais eficiente para arquivos grandes.
Drake Clarris
3
Acho que é isso que mais de 40 anos de otimização de muitos desses utilitários * nix você obterá!
Drake Clarris
@Gilles, é mais rápido o GNU sed em locais utf8 para algumas formas de entrada, e isso depende se você está considerando o tempo do relógio de parede ou o tempo da CPU. ssedou o baú da ferramenta Heirloom sedpode obter melhor desempenho.
Stéphane Chazelas
@Gilles Não há entrada MAN para revisão no Solaris 5.10. Acabei usandosed
ayrton_senna
10

Conforme sua pergunta, apague a última e a primeira palavra do arquivo de entrada, conforme abaixo:

sed 's/.$//; s/^.//' inputfile
Rahul Patil
fonte
Seria legal se você pudesse compará-las com a outra solução s/.\(.*\).$/\1/,. Pode ser mais rápido por não usar referências anteriores, e a pergunta mencionou "arquivos grandes".
precisa saber é
4
@ l0b0 eu testei com time yes | head -n 10000000 | COMMAND >/dev/null. Eu recebo rev input | cut -c2- | rev | cut -c2-→ 0.14s, sed 's,.\(.*\).$,\1,'→ 3.38s; awk '{print substr($0,2,length()-2);}'→ 3.50s; sed 's/.$//; s/^.//'→ 5.09s.
Gilles 'SO- stop be evil' (
@ Gilles +1 Essa deve ser uma resposta.
L0b0 11/01
2
@ Gilles, isso é linhas muito curtas. Acho que, para linhas de 30 caracteres, a solução da @ RahulPatil é três vezes mais rápida com o GNU sed do que a da @ juampa. Além disso. sed 's/.\(.*\)./\1/'parece ser mais rápido que sed 's/^.\(.*\).$/\1/'(GNU sed novamente). Além disso, o desempenho depende da localidade (interpretação do que é um personagem) e da sedimplementação (nesse sentido, sed do baú da ferramenta da herança é consideravelmente mais rápido que o GNU sed).
Stéphane Chazelas
5

Existem muitas possibilidades, como sempre

sed 's,.\(.*\).$,\1,g' your_file

Explicação

  • , - o delimitador sed, também pode ser qualquer outro caractere, pois é escapado onde quer que seja necessário.
  • . Corresponder a um único caractere
  • \(.*\) - Agrupe a parte restante e ela será armazenada para recuperação posterior.
  • . Corresponder um único caractere novamente
  • $ - Fim da linha
  • \1 - gera o texto correspondente ao grupo acima
  • g substituir globalmente na linha.
jpmuc
fonte
2
Por que g? haverá apenas uma correspondência por linha.
njsg
Observe que ele não removerá nada das linhas com menos de 2 caracteres.
Stéphane Chazelas
3

Você também pode fazer isso awkse preferir

awk '{print substr($0,2,length()-2);}' input.txt > output.txt
StrongBad
fonte
2
tr -d '()[]{}"' < your_file

Isso deve funcionar também. É bem "traduzir" cada um dos caracteres para nada (excluir).

A desvantagem é que eles serão excluídos se eles também não forem o primeiro / último caractere. Também perderá os caracteres finais que você não listar no ()[....

Mark Nichols
fonte