Format de sortie de xargs

10

Je voudrais changer le format des affichages xargs de sortie

cat k.txt 
1 
2 
3 

Et

cat k.txt | xargs 
1 2 3

Cependant, je voudrais avoir 1, 2, 3ou 1|2|3. Aucune suggestion?

Avinash
la source
Cela pourrait être réalisé avec quelque chose (pas exactement cela) xargs cat -n, mais c'est plus facile si vous coupez simplement les caractères de nouvelle ligne, cela peut être réalisé avec echo $(cat), grepou awk(explorez la façon de le faire). xargsne correspondent pas bien à votre objectif actuel.
41754

Réponses:

18

Vous trouverez ci-dessous une douzaine d'exemples sur la façon dont vous pouvez prendre un fichier tel que celui-ci:

$ cat k.txt
1
2
3

et convertissez-le dans ce format:

1,2,3

Vous pouvez utiliser cette commande pour créer le fichier ci-dessus si vous souhaitez jouer avec:

$ cat <<EOF > k.txt
1
2
3
EOF

Les exemples ci-dessous sont divisés en 2 groupes. Ceux qui "fonctionnent" et ceux qui "fonctionnent" presque. Je les laisse parce que souvent, il est tout aussi important de voir pourquoi quelque chose ne fonctionne pas, que de voir pourquoi quelque chose fonctionne.

La plupart des langages de script que je connais sont représentés. Certains sont représentés plusieurs fois, car comme avec le célèbre acronyme généralement référencé en Perl, TIMTOWTDI .

REMARQUE: vous pouvez échanger la virgule ( ,) dans les exemples ci-dessous et la remplacer par les caractères que vous souhaitez, c'est-à-dire |.

Exemples qui "fonctionnent"

Ces extraits de code produiront la sortie souhaitée.

La pastecommande:

$ paste -s -d ',' k.txt 
1,2,3

La sedcommande:

$ sed ':a;N;$!ba;s/\n/,/g' k.txt
1,2,3

$ sed ':a;{N;s/\n/,/};ba' k.txt 
1,2,3

La perlcommande:

$ perl -00 -p -e 's/\n(?!$)/,/g' k.txt
1,2,3

$ perl -00 -p -e 'chomp;tr/\n/,/' k.txt
1,2,3

La awkcommande:

$ awk '{printf"%s%s",c,$0;c=","}' k.txt
1,2,3

$ awk '{printf "%s,",$0}' k.txt | awk '{sub(/\,$/,"");print}'
1,2,3

$ awk -vORS=, 1 k.txt | awk '{sub(/\,$/,"");print}'
1,2,3

$ awk 'BEGIN {RS="dn"}{gsub("\n",",");print $0}' k.txt | awk '{sub(/\,$/,"");print}'
1,2,3

La pythoncommande:

$ python -c "import sys; print sys.stdin.read().replace('\n', ',')[0:-1]" <k.txt
1,2,3

$ python -c "import sys; print sys.stdin.read().replace('\n', ',').rstrip(',')" <k.txt
1,2,3

Intégré de Bash mapfile:

$ mapfile -t a < k.txt; (IFS=','; echo "${a[*]}")
1,2,3

La rubycommande:

$ ruby -00 -pe 'gsub /\n/,",";chop' < k.txt
1,2,3

$ ruby -00 -pe '$_.chomp!"\n";$_.tr!"\n",","' k.txt
1,2,3

La phpcommande:

$ php -r 'echo strtr(chop(file_get_contents($argv[1])),"\n",",");' k.txt
1,2,3

Avertissements

La plupart des exemples ci-dessus fonctionneront très bien. Certains ont des problèmes cachés, comme l'exemple PHP ci-dessus. La fonction chop()est en fait un alias rtrim(), donc les espaces de fin de la dernière ligne seront également supprimés.

Il en va de même pour le premier exemple Ruby et le premier exemple Python. Le problème est de savoir comment ils utilisent tous un type d'opération qui "coupe" aveuglément un caractère de fin. C'est très bien dans l'exemple fourni par l'OP, mais il faut faire attention lors de l'utilisation de ces types de doublures pour s'assurer qu'elles sont conformes aux données qu'elles traitent.

Exemple

Disons que notre exemple de fichier k.txtressemble à ceci:

$ echo -en "1\n2\n3" > k.txt

Il ressemble mais a une légère différence. Il n'a pas de nouvelle ligne ( \n) comme le fichier d'origine. Maintenant, lorsque nous exécutons le premier exemple Python, nous obtenons ceci:

$ python -c "import sys; print sys.stdin.read().replace('\n', ',')[0:-1]" <k.txt
1,2,

Exemples qui fonctionnent "presque"

Ce sont les exemples "toujours une demoiselle d'honneur, jamais une mariée" . La plupart d'entre eux pourraient probablement être adaptés, mais lorsque vous travaillez sur une solution potentielle à un problème, quand il se sent "forcé", ce n'est probablement pas le bon outil pour le travail!

La perlcommande:

$ perl -p -e 's/\n/,/' k.txt
1,2,3,

La trcommande:

$ tr '\n' ','  < k.txt 
1,2,3,

Les commandes cat+ echo:

$ echo $(cat k.txt)
1 2 3

La rubycommande:

$ ruby -pe '$_["\n"]=","' k.txt
1,2,3,

Bash's while+ readintégrés:

$ while read line; do echo -n "$line,"; done < k.txt
1,2,3,
slm
la source
1
Concernant awkje préfère une alternative plus courte:awk -vORS=, 1 k.txt
manatwork
Je ne sais pas si CentOS a bash:mapfile -t a < k.txt; (IFS=','; echo "${a[*]}")
manatwork
pas sûr de la nouvelle ligne de fin. Selon mon test, vous en avez d' perlabord awk.
manatwork
Je mettrais pastecelui en haut. C'est exactement paste -spour ça. C'est une commande standard et ce serait la plus efficace. Tous les autres sont exagérés et / ou ne sont pas portables ou ont des limitations.
Stéphane Chazelas
mapfileest relativement nouveau, ajouté en bash4.0.
manatwork
4

@slm a déjà donné une bonne réponse, mais comme votre question "format de sortie de xargs"

xargs -I{} echo -n "{}|" < test.txt
  • -I est l'option "remplacer les chaînes".
  • {} est un espace réservé pour le texte de sortie.
  • Ceci est similaire à l'utilisation d'une paire d'accolades dans "find".

Si vous voulez vous débarrasser de la fuite, |vous pouvez l'utiliser sedpour nettoyer:

$ xargs -I{} echo -n "{}|" < k.txt  | sed -e 's/|$//'
1|2|3
Rahul Patil
la source
Cela claque un tuyau supplémentaire après le 3. "1 | 2 | 3 |". J'ai eu le même problème avec une boucle while et une solution awk.
slm
oui, s'il y a une nouvelle ligne .. tr, sedet d'autres aussi ..
Rahul Patil
2

C'est un vieux fil, je sais. L'OP a demandé avec un code simple comme celui-ci. Pour le garder proche de l'original, j'ai une solution simple.

cat k.txt | xargs
1 2 3

utiliser sed

cat k.txt | xargs | sed 's/ /,/g'
1,2,3

ou

cat k.txt | xargs | sed 's/ /|/g'
1|2|3

sed peut sembler un peu bizarre mais en panne, cela a beaucoup de sens.

c'est pour remplacer. g 'est pour global: sans cela, il ne fera que la première substitution sur chaque nouvelle ligne. Puisque vous utilisez 'xargs', il les affiche sur une seule ligne. Vous obtiendrez donc "1,2 3".

Le délimiteur est utilisé pour la séparation. J'ai utilisé le caractère /. Une astuce intéressante: vous pouvez remplacer le délimiteur par la plupart des autres caractères, tant que nous conservons le même format entre les guillemets. Cela fonctionnerait donc aussi ...

cat k.txt | xargs | sed 's# #,#g'

ou

cat k.txt | xargs | sed 'sT T,Tg'

De toute évidence, l'utilisation de certains caractères comme délimiteur peut être source de confusion, alors soyez intelligent.

Michael Bruce
la source
0
xargs <k.txt | tr \  \|

Vous n'avez pas besoin cat- passez simplement l'entrée du fichier et - si aucune autre commande ne vous est donnée - xargspassera son format par défaut - qui est du type avec /bin/echo's (sans les interprétations de c-escape antislash) .

xargssupprimera les espaces blancs tête / queue du fichier d'entrée et compressera les autres séquences d'espaces blancs en un seul espace. Cela signifie qu'en passant le fichier de trto xargslike:

tr \\n \| <k.txt | xargs

... impressions ...

1|2|3|

... aller dans l'autre sens et fonctionner uniquement sur les arguments que l' xargsespace-délimite fait ....

1|2|3\n

... car xargsimprime le retour à la ligne final final (comme cela est requis pour un fichier texte) , mais il n'est pas trtraité de cette façon.

Notez cependant que cela (ou toute autre solution proposée ici) ne tient pas compte des xargscitations en entrée. xargspassera littéralement des caractères d'espacement non-retour à la ligne simples / doubles / avec barre oblique inverse en entrée, qui peuvent eux-mêmes être cités comme:

xargs <<\IN
1    2'      3'\'      \'4
IN

1 2      3' '4
mikeserv
la source