web-dev-qa-db-fra.com

Comment trier par rangée de terminal

Je regardais cette question et je me suis demandé si ce qui suit pouvait être fait depuis le terminal. Je l'ai fait en python, je veux juste voir si cela pourrait être fait à partir d'un terminal, d'un script bash ou autre.

Supposons que j'ai un fichier qui ressemble à ceci:

2,4,5,14,9
40,3,5,10,1

pourrait-il être trié comme tel, par rangées (lignes)

2,4,5,9,14
1,3,5,10,40

ou est-ce trop compliqué? Je l'ai fait en utilisant python, je veux juste savoir si cela pourrait être fait afin que je ne puisse pas utiliser la prochaine fois. Ce que j'ai fait, c'est créer des listes et les trier.

7
Lynob

Voici une autre approche Perl:

Perl -F, -lane 'print join ",",sort {$a<=>$b} @F' file.txt

Et un autre Shell/coreutils (bien que personnellement, je préfère l'acier excellente réponse qui utilise la même idée):

while read line; do 
    tr , $'\n' < <(printf -- "%s" "$line") | sort -g | tr $'\n' , | sed 's/,$/\n/';
done < file.txt
5
terdon

Cela devrait faire ce que vous cherchez. Il lira un fichier (test.txt) et créera un fichier de sortie (trié.txt) avec les lignes triées dans le même ordre d'apparition dans le fichier d'origine.

while read line; do j=$(echo "$line" | sed -e 's/,/\n/g' | sort -n); echo "$j" 
    | sed -e 's/ /,/g' >> sorted.txt; done < test.txt
7
jkt123

Voici une solution awk,

while read -r line; do (echo $line | awk '{ n=split($1,a,","); asort(a); for(i=0;i<=n;i++) { print a[i];}}') | xargs | sed -e 's/ /,/g'; done < text.txt

Explication:

  • awk '{ n=split($1,a,","); asort(a); for(i=0;i<=n;i++) { print a[i];}}'

    awk Divise le champ 1 en fonction du délimiteur , et enregistre chaque valeur dans le tableau a enfin la position la plus haute est enregistrée dans la variable n. La fonction asort(a) suivante trie les valeurs du tableau. Ensuite, la boucle for de la commande awk imprime les valeurs triées au format enregistrement par enregistrement.

  • xargs | sed -e 's/ /,/g'

    xargs combine toutes les lignes en une seule ligne.

  • sed -e 's/ /,/g'

    Il remplace les espaces par des virgules ,

  • while read -r line;

    Toutes les fonctions awk, xargs, sed ci-dessus sont effectuées ligne par ligne à l'aide de la boucle while.

4
Avinash Raj

La seule vraie difficulté à faire ce que vous voulez en utilisant un script en ligne de commande est que la fonction sort disponible s'attend à trier lignes dans un fichier, plutôt que champs dans une ligne. Pour contourner ce problème, vous pouvez remplacer les délimiteurs de champs ligne par ligne par des nouvelles lignes précédant la fonction sort, puis remplacer les nouvelles lignes par des délimiteurs dans chaque ligne après le tri.

Il existe un certain nombre d’utilitaires de traitement de texte disponibles qui vous permettraient de le faire (y compris sed, awk, ou même le simple tr), mais le bash Shell lui-même peut faire beaucoup de choses de nos jours. . En supposant que vous vouliez que l'entrée soit délimitée par des virgules (vous avez un mélange de virgules et de délimiteurs d'espaces dans votre exemple), vous pouvez effectuer les opérations suivantes:

while read line; do 
  sorted=$(sort -g -- <<< "${line//,/$'\n'}")
  printf -- "${sorted//$'\n'/,}\n"
done < file

Si vous do devez gérer les délimiteurs d'espace dans l'entrée, vous pouvez les ajouter en tant que partie d'une liste de caractères [, ] pour le remplacement de la sous-chaîne d'entrée:

while read line; do 
  sorted=$(sort -g -- <<< "${line//[, ]/$'\n'}")
  printf -- "${sorted//$'\n'/,}\n"
done < file

(notez que le résultat reste strictement délimité par des virgules).

4
steeldriver

Utiliser tr et sed

Semblable en esprit à ce que jkt123 a écrit :

while read i; do tr , \\n <<< $i | sort -n | tr \\n , | sed 's/,$//'; done

Il effectue une itération sur les lignes et pour chaque ligne remplace les virgules par des nouvelles lignes, trie les lignes résultantes numériquement, puis redéfinit les nouvelles lignes en virgules. Le principal problème est que cela mettra fin au résultat complet avec une virgule et non une nouvelle ligne, qui est traitée par ce dernier. Il supprime la dernière virgule et ajoute implicitement une nouvelle ligne à sa sortie.

Utiliser des tableaux bash

Voici une approche différente pour traiter ce problème de "joindre avec des virgules":

while read i; do j=( $(tr , \\n <<< $i | sort -n) ); ( IFS=,; echo "${j[*]}"; ); done

Ou écrit avec des retours à la ligne:

while read i
do
   j=( $(tr , \\n <<< $i | sort -n) )
   ( IFS=,; echo "${j[*]}"; )
done

Il utilise un tableau bash pour stocker le résultat de la ligne triée et utilise la façon dont bash développe les tableaux en littéraux de chaîne à l'aide de la variable spéciale IFS.

3
MvG

python -c "your code here" input.txt

Ou, si votre programme a plusieurs lignes et que eval() est trop lent:

python yourprogram.py input.txt

Cet oneliner fonctionne:

python -c "for l in open('input.txt'):print(','.join(sorted(l.strip().split(','), key=int)))"
3
Cees Timmerman

Le le plus court solution utilisant un onliner Perl:

Perl -ne 'print join(",", sort { $a <=> $b } split(/,|\n/))."\n"' text.txt
2
Sylvain Pineau

Vous pouvez le faire facilement en utilisant Perl

considérez que vous avez le fichier text.txt

cat text.txt

1,5,7,8,3,6
10,34,67,1,2,0,5

Maintenant, le code Perl suivant va trier les lignes dans text.txt

 Perl -i -e 'while(<>){chomp; my @sorted = sort { $a <=> $b } split(",", $_); print join (",", @sorted); print "\n"}' text.txt

Après le tri

cat text.txt

1,3,5,6,7,8
0,1,2,5,10,34,67
2
Stormvirux

J'avais aussi besoin de cette fonctionnalité et une solution que j'ai trouvée est la suivante (en supposant que les données sont dans le fichier de test):

cat test | while read line; do echo $(echo $line | datamash -t',' transpose |sort -g| datamash -t',' transpose); done
1
Eissa N.