Trier un fichier texte par la longueur de la ligne, espaces compris
J'ai un fichier CSV qui ressemble à ce
AS2345,ASDF1232, M. Plaine Exemple, 110 Binaire ave.,Atlantis,RI,12345,(999)123-5555,à 1,56 AS2345,ASDF1232, Mme la Plaine Exemple, 1121110 Ternaire saint. 110 Binaire ave..,Atlantis,RI,12345,(999)123-5555,à 1,56 AS2345,ASDF1232, M. Plaine Exemple, 110 Binaire ave.,Liberty City,RI,12345,(999)123-5555,à 1,56 AS2345,ASDF1232, M. Plaine Exemple, 110 Ternaire ave.,Certains de la Ville,RI,12345,(999)123-5555,à 1,56
J'ai besoin de faire le tri par la longueur de la ligne, espaces compris. La commande suivante n'est pas
inclure des espaces, est-il un moyen de le modifier afin qu'il fonctionne pour moi?
cat $@ | awk '{ print length, $0 }' | sort -n | awk '{$1=""; print $0}'
- J'aimerais vraiment vivre en Binaire Avenue ou Ternaire de la Rue, ces gens pourrait certainement être d'accord avec des choses comme "8192 est un chiffre rond"
Vous devez vous connecter pour publier un commentaire.
Réponse
Ou, pour faire votre original (peut-être involontaire) sous-tri de l'égalité de longueur des lignes:
Dans les deux cas, nous avons résolu votre problème en déplaçant loin de awk pour votre montage final.
Lignes de correspondance de longueur - que faire en cas d'égalité:
La question ne précise pas si ou non de poursuivre le tri a été voulu pour les lignes de correspondance de longueur. J'ai supposé que c'est non désirés et a suggéré l'utilisation de
-s
(--stable
) pour prévenir de telles lignes à trier les uns contre les autres, et de les garder dans l'ordre dans lequel ils se produisent dans l'entrée.(Ceux qui veulent plus de contrôle sur le tri de ces liens pourrait ressembler au tri
--key
option.)Pourquoi la question des tentatives de solution échoue (awk ligne-reconstruction):
Il est intéressant de noter la différence entre:
Qu'ils cèdent respectivement
La la section pertinente de l' (gawk s) du manuel ne mentionne en passant que awk va reconstruire l'ensemble de 0 $(basé sur le séparateur, etc) lorsque vous modifiez un champ. Je suppose que ce n'est pas fou de comportement. Il a ceci:
"Enfin, il y a des moments où il est commode de force awk pour reconstruire la totalité de l'enregistrement, à l'aide de la valeur actuelle des champs et de l'OFS. Pour ce faire, utilisez l'apparence anodine d'affectation:"
"Cette les forces de awk pour reconstruire le dossier".
Test d'entrée, y compris certaines lignes d'égale longueur:
awk
alternative.cat $@
est cassé, trop. Vous absolument certainement envie de le citer, commecat "$@"
La AWK solution de neillb est l'endroit idéal si vous voulez vraiment utiliser
awk
et il explique pourquoi il est fastidieux de là, mais si ce que vous voulez est de faire le travail rapidement et ne se soucient pas ce que vous faites cela, une solution consiste à utiliser Perlsort()
fonction avec une coutume caparison routine pour itérer sur les lignes d'entrée. Voici en une seule ligne:Vous pouvez mettre ceci dans votre pipeline partout où vous en avez besoin, à la réception de STDIN (à partir de
cat
ou à une coque de redirection) ou tout simplement donner le nom du fichier à perl comme un autre argument et le laisser ouvert le fichier.Dans mon cas, j'avais besoin de la plus longue premières lignes, j'ai donc échangé
$a
et$b
dans la comparaison.Essayer cette commande au lieu de:
Les résultats d'un Benchmark
Ci-dessous sont les résultats d'une référence dans les solutions de ather réponses à cette question.
Méthode d'essai
Résultats
perl
solution a pris 11.2 secondesperl
solution a pris 11.6 secondesawk
solution #1 a pris 20 secondesawk
solution #2 a 23 secondesawk
solution pris 24 secondesawk
solution a pris 25 secondesbash
solution prend 400 fois plus long que leawk
solutions (à l'aide d'un tronc de cas de test de 100000 lignes). Il fonctionne très bien, faut juste jamais.Supplémentaire
perl
optionAussi, j'ai ajouté un autre Perl solution:
Pur Bash:
La
length()
fonction ne contenir d'espaces. Je voudrais simplement faire des ajustements mineurs à votre pipeline (notamment en évitant les UUOC).La
sed
commande directement supprime les chiffres et les deux points ajoutés par leawk
de commande. Sinon, en gardant votre mise en forme deawk
:J'ai trouvé ces solutions ne fonctionne pas si votre fichier contient des lignes qui commencent par un nombre, car ils seront triés numériquement avec tous les compté les lignes. La solution est de donner
sort
la-g
(général-numérique-tri) drapeau au lieu de-n
(numérique-tri):-n
à votre suggestion de-g
à obtenir une amélioration, donc je m'attends pas. J'ai désormais l'objet, dans ma réponse, comment interdire la sous-tri de l'égalité de longueur des lignes (à l'aide de--stable
). Si oui ou non c'était ce que tu voulais dire, merci de le signaler à mon attention! J'ai aussi ajouté une entrée pour le test.awk
partie pour générer une liste de lignes commençant avec la longueur de la ligne et un espace. Tuyauterie àsort -n
fonctionnera comme prévu. Mais si l'un de ces lignes a déjà un certain nombre au début, ces lignes vont commencer avec la longueur + espace + le numéro.sort -n
ne tient pas compte que l'espace et le traiter comme un numéro de concaténées partir d'une longueur de + numéro. À l'aide de la-g
drapeau de la volonté au lieu de s'arrêter à la première place, ce qui donne un tri correct. Essayez-le vous-même par la création d'un fichier avec un certain nombre de préfixe de lignes et d'exécuter la commande, étape par étape.sort -n
abstraction de l'espace et produit un tri incorrect.sort -g
sorties le bon ordre.-n
danssort (GNU coreutils) 8.21
. Leinfo
documentation décrit-g
moins efficace, et potentiellement moins précis (il convertit les numéros de flotte), alors, probablement, ne l'utilisez pas si vous n'en avez pas besoin.-n
: "Trier numériquement. Le numéro commence chaque ligne et consiste en option blancs, en option, un signe" -", et zéro ou plusieurs chiffres, éventuellement séparés par des séparateurs de milliers, suivie éventuellement par une virgule point de caractère et de zéro ou plusieurs chiffres. Un vide nombre est considéré comme ‘0’. Le " LC_NUMERIC locale spécifie le séparateur décimal point de caractère et le séparateur des milliers. Par défaut, un vide est un espace ou une tabulation, mais le "LC_CTYPE locale peut changer cela".LC_ALL=C sort -n
Avec POSIX Awk:
Exemple
1) pur awk solution. Supposons que la longueur de la ligne ne peut pas être plus > 1024
puis
chat de nom de fichier | awk 'BEGIN {min = 1024; s = "";} {l = length($0); si (l < min) {min = l; s = $0;}} END {print s}'
2) une ligne de bash solution en supposant que toutes les lignes ont juste 1 mot, mais peut retravaillé pour tous les cas où toutes les lignes ont le même nombre de mots:
LIGNES=$(cat nom_fichier); pour k dans $LIGNE; do printf "$k "; echo $k | wc-L; done | sort-k2 | head-n 1 | cut-d "" -f1
Ici est un multi-octets compatible avec la méthode des lignes de tri par longueur. Il faut pour cela:
wc -m
est disponible pour vous (macOS a).LC_ALL=UTF-8
. Vous pouvez définir ce soit dans votre .bash_profile, ou simplement en ajoutant avant la commande suivante.testfile
a un codage de caractères correspondant à vos paramètres régionaux (par exemple, UTF-8).Voici l'intégralité de la commande:
Expliquant en partie par partie:
l=$0; gsub(/\047/, "\047\"\047\"\047", l);
← fait d'une copie de chaque ligne dans awk variablel
et double-échappe à tous les'
de sorte que la ligne peut en toute sécurité être repris comme un shell de commande (\047
est un guillemet simple dans la notation octale).cmd=sprintf("echo \047%s\047 | wc -m", l);
← c'est la commande que nous allons exécuter, qui fait écho à l'échappé de la ligne dewc -m
.cmd | getline c;
← exécute la commande et copies le nombre de caractères de la valeur qui est retournée dans la variable awkc
.close(cmd);
← fermer le tuyau pour la commande shell pour éviter de heurter un système de limite sur le nombre de fichiers ouverts dans un processus.sub(/*/, "", c);
← garnitures espace blanc au nombre de caractères de la valeur retournée parwc
.{ print c, $0 }
← imprime la ligne du nombre de caractères de la valeur, de l'espace, et la ligne d'origine.| sort -ns
← trie les lignes (par préfixé nombre de caractères valeurs) numériquement (-n
), et le maintien de la stabilité de l'ordre de tri (-s
).| cut -d" " -f2-
← supprime la préfixé nombre de caractères valeurs.C'est lent (seulement 160 lignes par seconde sur un rapide Macbook Pro), car il doit exécuter une sous-commande pour chaque ligne.
Sinon, il suffit de faire cela uniquement avec
gawk
(de la version 3.1.5, gawk est multi-octets au courant), ce qui serait nettement plus rapide. Il a beaucoup de difficulté à le faire tous les fuir et double-échappement en toute sécurité passer les lignes à l'aide d'une commande shell à partir de awk, mais c'est la seule méthode que j'ai pu trouver qui ne nécessite pas l'installation de logiciels supplémentaires (gawk n'est pas disponible par défaut sur macOS).