Eu tenho um arquivo CSV parecido com este
AS2345, ASDF1232, Mr. Plain Example, 110 Binary ave., Atlantis, RI, 12345, (999) 123-5555,1,56 AS2345, ASDF1232, Sra. Plain Example, 1121110 Ternary st. 110 Binary ave .., Atlantis, RI, 12345, (999) 123-5555,1,56 AS2345, ASDF1232, Mr. Plain Example, 110 Binary ave., Liberty City, RI, 12345, (999) 123-5555,1,56 AS2345, ASDF1232, Mr. Plain Example, 110 Ternary ave., Some City, RI, 12345, (999) 123-5555,1,56
Preciso classificá-lo por comprimento de linha, incluindo espaços. O comando a seguir não inclui espaços. Existe uma maneira de modificá-lo para que funcione para mim?
cat $@ | awk '{ print length, $0 }' | sort -n | awk '{$1=""; print $0}'
Respostas:
Responda
Ou, para fazer sua sub-classificação original (talvez não intencional) de qualquer linha de igual comprimento:
Em ambos os casos, resolvemos o seu problema declarado, afastando o awk para o seu corte final.
Linhas de comprimento correspondente - o que fazer em caso de empate:
A pergunta não especificou se era necessária uma classificação adicional para linhas de comprimento correspondente. Eu assumi que isso é indesejável e sugeri o uso de
-s
(--stable
) para impedir que essas linhas sejam classificadas uma contra a outra e mantenha-as na ordem relativa em que elas ocorrem na entrada.(Aqueles que desejam mais controle sobre a classificação desses vínculos podem procurar a
--key
opção de classificação .)Por que a tentativa de solução da pergunta falha (awk line-reconstruction):
É interessante notar a diferença entre:
Eles produzem respectivamente
A seção relevante do manual (gawk's) menciona apenas um aparte que o awk reconstruirá todo o valor de US $ 0 (com base no separador, etc.) quando você alterar um campo. Eu acho que não é um comportamento louco. Tem o seguinte:
"Finalmente, há momentos em que é conveniente forçar o awk a reconstruir todo o registro, usando o valor atual dos campos e do OFS. Para fazer isso, use a atribuição aparentemente inócua:"
"Isso força o awk a reconstruir o registro."
Entrada de teste, incluindo algumas linhas de igual comprimento:
fonte
cat $@
está quebrado. Você definitivamente definitivamente quer citá-lo, comocat "$@"
A solução AWK da neillb é ótima se você realmente deseja usar
awk
e explica por que é um aborrecimento, mas se o que você quer é fazer o trabalho rapidamente e não se importar com o que faz, uma solução é usarsort()
Função do Perl com uma rotina caparison personalizada para iterar nas linhas de entrada. Aqui está um liner:Você pode colocar isso no seu pipeline sempre que precisar, recebendo STDIN (de
cat
ou um redirecionamento de shell) ou apenas dando o nome do arquivo para perl como outro argumento e deixe abrir o arquivo.No meu caso, eu precisava das linhas mais longas primeiro, então troquei
$a
e$b
comparei.fonte
cat testfile.txt | perl -e 'print sort { length($a) <=> length($b) } <>' > out.txt
type testfile.txt | perl -e "print sort { length($a) <=> length($b) } <>" > out.txt
Tente este comando:
fonte
Resultados de referência
Abaixo estão os resultados de uma referência entre as soluções de outras respostas a esta pergunta.
Método de teste
Resultados
perl
solução de Caleb levou 11,2 segundosperl
solução levou 11,6 segundosawk
solução nº 1 de neillb levou 20 segundosawk
solução nº 2 de neillb levou 23 segundosawk
solução de anubhava levou 24 segundosawk
solução de Jonathan levou 25 segundosbash
solução da Fretz leva 400x mais tempo do que asawk
soluções (usando um caso de teste truncado de 100000 linhas). Funciona bem, leva apenas uma eternidade.perl
Opção extraAlém disso, adicionei outra solução Perl:
fonte
Pure Bash:
fonte
A
length()
função inclui espaços. Eu faria apenas pequenos ajustes no seu pipeline (incluindo evitar o UUOC ).O
sed
comando remove diretamente os dígitos e dois pontos adicionados peloawk
comando. Como alternativa, mantendo sua formatação deawk
:fonte
Descobri que essas soluções não funcionarão se o seu arquivo contiver linhas que começam com um número, pois serão classificadas numericamente junto com todas as linhas contadas. A solução é fornecer
sort
o-g
sinalizador-n
( classificação numérica geral) em vez de (classificação numérica):fonte
-n
para os sugeridos-g
resultasse em melhorias, portanto espero que não. Agora, na minha resposta, eu lidei como proibir a classificação secundária de linhas de comprimento igual (usando--stable
). Quer fosse ou não o que você quis dizer, obrigado por chamar minha atenção! Também adicionei uma entrada considerada para testar.awk
peça irá gerar uma lista de linhas prefixadas com o comprimento da linha e um espaço. A tubulaçãosort -n
funcionará conforme o esperado. Mas se alguma dessas linhas já tiver um número no início, essas linhas começarão com comprimento + espaço + número.sort -n
desconsidera esse espaço e o trata como um número concatenado de comprimento + número. O uso da-g
bandeira será interrompido no primeiro espaço, produzindo uma classificação correta. Tente você mesmo criando um arquivo com algumas linhas com prefixo numérico e execute o comando passo a passo.sort -n
desconsidera o espaço e produz uma classificação incorreta.sort -g
gera a ordem correta.-n
insort (GNU coreutils) 8.21
. Ainfo
documentação é descrita-g
como menos eficiente e potencialmente menos precisa (converte números em flutuadores); portanto, provavelmente não a use se não for necessário.-n
: "Classificar numericamente. O número inicia cada linha e consiste em espaços em branco opcionais, um sinal '-' opcional e zero ou mais dígitos possivelmente separados por separadores de milhares, opcionalmente seguido por um caractere de ponto decimal e zero ou mais dígitos . Um número vazio é tratado como '0'. O código de idioma 'LC_NUMERIC' especifica o caractere de ponto decimal e o separador de milhares. Por padrão, um espaço em branco é um espaço ou uma guia, mas o código de idioma 'LC_CTYPE' pode alterar isso. "Com o POSIX Awk:
Exemplo
fonte
1) solução awk pura. Vamos supor que o comprimento da linha não possa ser maior que 1024
nome do arquivo cat | awk 'COMEÇA {min = 1024; s = "";} {l = comprimento ($ 0); se (l <min) {min = l; s = $ 0;}} END {print s} '
2) uma solução bash de liner assumindo que todas as linhas têm apenas 1 palavra, mas pode ser retrabalhada para qualquer caso em que todas as linhas tenham o mesmo número de palavras:
LINHAS = $ (nome do arquivo do gato); para k em $ LINES; faça printf "$ k"; eco $ k | wc -L; feito | classificar -k2 | cabeça -n 1 | cut -d "" -f1
fonte
Aqui está um método compatível com vários bytes de classificação de linhas por comprimento. Isso requer:
wc -m
está disponível para você (o macOS possui).LC_ALL=UTF-8
. Você pode configurá-lo no seu .bash_profile ou simplesmente acrescentando-o antes do comando a seguir.testfile
possui uma codificação de caracteres que corresponde ao seu código do idioma (por exemplo, UTF-8).Aqui está o comando completo:
Explicando parte por parte:
l=$0; gsub(/\047/, "\047\"\047\"\047", l);
← faz uma cópia de cada linha na variável awkl
e escapa duas vezes a cada,'
para que a linha possa ecoar com segurança como um comando shell (\047
é uma aspas simples na notação octal).cmd=sprintf("echo \047%s\047 | wc -m", l);
← este é o comando que executaremos, que ecoa a linha escapada parawc -m
.cmd | getline c;
← executa o comando e copia o valor da contagem de caracteres retornado para a variável awkc
.close(cmd);
← feche o canal no comando shell para evitar atingir um limite do sistema no número de arquivos abertos em um processo.sub(/ */, "", c);
← corta o espaço em branco do valor da contagem de caracteres retornado porwc
.{ print c, $0 }
← imprime o valor da contagem de caracteres da linha, um espaço e a linha original.| sort -ns
← classifica as linhas (pelos valores de contagem de caracteres acrescentados) numericamente (-n
) e mantém a ordem de classificação estável (-s
).| cut -d" " -f2-
← remove os valores de contagem de caracteres anexados.É lento (apenas 160 linhas por segundo em um Macbook Pro veloz) porque deve executar um subcomando para cada linha.
Como alternativa, faça isso apenas com
gawk
(a partir da versão 3.1.5, o gawk reconhece multibytes), o que seria significativamente mais rápido. É muito difícil fazer todas as escapadas e aspas duplas para passar com segurança as linhas através de um comando shell do awk, mas esse é o único método que eu pude encontrar que não requer a instalação de software adicional (o gawk não está disponível por padrão em Mac OS).fonte