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.
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
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
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
.
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).
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.
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
.
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)))"
Le le plus court solution utilisant un onliner Perl:
Perl -ne 'print join(",", sort { $a <=> $b } split(/,|\n/))."\n"' text.txt
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
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