Comment concaténer plusieurs lignes de sortie sur une seule ligne?

157

Si j'exécute la commande cat file | grep pattern, j'obtiens de nombreuses lignes de sortie. Comment concaténer toutes les lignes en une seule ligne, en remplaçant efficacement chacune "\n"par "\" "(fin par "suivi d'un espace)?

cat file | grep pattern | xargs sed s/\n/ /g ne fonctionne pas pour moi.

T. Webster
la source
Au fait: (1) vous devez mettre votre sedscript entre guillemets simples pour que Bash ne le dérange pas (puisque les sed s/\n/ /gappels sedavec deux arguments, à savoir s/n/et /g); (2) puisque vous voulez la sortie cat file | grep patternêtre l' entrée à sed, pas les arguments à sed, vous devez éliminer xargs; et (3) ce n'est pas nécessaire catici, car greppeut prendre un nom de fichier comme deuxième argument. Donc, vous auriez dû essayer grep pattern file | sed 's/\n/ /g'. (Dans ce cas, cela n'aurait pas fonctionné, pour les raisons données sur le lien ci-dessus, mais maintenant vous savez pour l'avenir.)
ruakh
similaire à " stackoverflow.com/questions/2764051/... "
Shervin Emami
Question avec 68 votes (140k vues) dupliquée avec un post qui n'a qu'un vote (12k vues)? Ce n'est pas juste.
kenorb

Réponses:

230

Utilisez tr '\n' ' 'pour traduire tous les caractères de nouvelle ligne en espaces:

$ grep pattern file | tr '\n' ' '

Remarque: greplit les fichiers, catconcatène les fichiers. Pas cat file | grep!

Éditer:

trne peut gérer que les traductions d'un seul caractère. Vous pouvez utiliser awkpour changer le séparateur d'enregistrement de sortie comme:

$ grep pattern file | awk '{print}' ORS='" '

Cela transformerait:

one
two 
three

à:

one" two" three" 
Chris Seymour
la source
3
Vous vous retrouvez avec un espace indésirable à la fin avec cette approche.
sorin
1
Vous devez ajouter echo ""à la fin pour ajouter une nouvelle ligne avant le texte d'invite.
nexayq
1
Cela fonctionne bien, mais je ne veux pas que le séparateur apparaisse sur la toute dernière entrée. Exemple, selon votre ", il apparaît comme one" two" three", mais je voudrais qu'il apparaisse comme one" two" three. Notez que les trois derniers n'ont pas de parenthèses. Des idées?
oink
2
@oink vous pouvez diriger les résultats vers sed '$s/..$//'pour supprimer les 2 derniers caractères de la dernière ligne.
Chris Seymour
3
Si vous souhaitez remplacer les nouvelles lignes par rien, vous devez utiliser l' --deleteoption car la valeur par défaut attend deux arguments. par exemple tr --delete '\n'.
Elijah Lynn
69

La sortie de tuyauterie vers xargsconcaténera chaque ligne de sortie en une seule ligne avec des espaces:

grep pattern file | xargs

Ou n'importe quelle commande, par exemple. ls | xargs. La limite de xargssortie par défaut est d'environ 4096 caractères, mais peut être augmentée avec par exemple. xargs -s 8192.

bluebadge
la source
| tr '\n' ' 'ne fonctionnait pas pour moi lorsqu'il est appelé via la php execfonction. Il ignorait tr, et donnait juste le dernier match de grep. | xargstravaillé.
Adarsha
3
Cette solution a également l'avantage de «manger» des espaces de l'entrée. +1
Rene
55

Dans bash echosans guillemets, supprimez les retours chariot, les tabulations et les espaces multiples

echo $(cat file)
user1699917
la source
8
Réponse gravement sous-estimée ici, c'est vraiment simple et fonctionne comme un charme, avec une nouvelle ligne de fuite également.
Dangercrow
Ceci est particulièrement IFS="$(printf '\n\t')"
intéressant
5
Ou simplement echo $(<file)... utiliser l'écho n'est pas seulement plus soigné que l'utilisation tr '\n' ' ', mais aussi mieux (pensez aux \r\nfins de ligne). @aggsol vous pouvez juste direIFS=$'\n\t'
Normadize
Et sans espace?
DimiDak
22

Cela pourrait être ce que tu veux

cat file | grep pattern | paste -sd' '

Quant à votre modification, je ne suis pas sûr de ce que cela signifie, peut-être ceci?

cat file | grep pattern | paste -sd'~' | sed -e 's/~/" "/g'

(cela suppose que ~cela ne se produit pas dans file)

sehe
la source
2
@Stephan il n'était pas nécessaire de supposer que ce cat filesera réellement cat, ni même un fichier. (Je viens de quitter cette partie inchangée car il était hors de propos à la question)
sehe
5

Ceci est un exemple qui produit une sortie séparée par des virgules. Vous pouvez remplacer la virgule par le séparateur dont vous avez besoin.

cat <<EOD | xargs | sed 's/ /,/g'
> 1
> 2
> 3
> 4
> 5
> EOD

produit:

1,2,3,4,5
Richard Gomes
la source
3

Voici la méthode utilisant l' exéditeur (partie de Vim ):

  • J oin toutes les lignes et p Rint à la sortie standard:

    $ ex +%j +%p -scq! file
  • J oin toutes les lignes en place (dans le fichier):

    $ ex +%j -scwq file

    Remarque: Cela concaténera toutes les lignes à l'intérieur du fichier lui-même!

Kenorb
la source
2

Les moyens les plus rapides et les plus simples que je connaisse pour résoudre ce problème:

Lorsque nous voulons remplacer le caractère de nouvelle ligne \n par l'espace :

xargs < file

xargsa ses propres limites sur le nombre de caractères par ligne et le nombre de tous les caractères combinés, mais nous pouvons les augmenter. Les détails peuvent être trouvés en exécutant cette commande: xargs --show-limitset bien sûr dans le manuel:man xargs

Lorsque nous voulons remplacer un caractère par un autre exactement un caractère :

tr '\n' ' ' < file

Lorsque nous voulons remplacer un caractère par plusieurs caractères :

tr '\n' '~' < file | sed s/~/many_characters/g

Tout d'abord, nous remplaçons les caractères de nouvelle ligne \npour les tildes ~(ou choisissons un autre caractère unique non présent dans le texte), puis nous remplaçons les caractères tilde par d'autres caractères ( many_characters) et nous le faisons pour chaque tilde (drapeau g).

simhumileco
la source
0

La meilleure façon de le faire est probablement d'utiliser l'outil 'awk' qui générera une sortie sur une ligne

$ awk ' /pattern/ {print}' ORS=' ' /path/to/file

Il fusionnera toutes les lignes en une seule avec un délimiteur d'espace

Vladimir Yahello
la source
Vous n'en avez pas besoin {print}puisque c'est l'action par défaut de awk.
Stark
0

Voici une autre méthode simple utilisant awk:

# cat > file.txt
a
b
c

# cat file.txt | awk '{ printf("%s ", $0) }'
a b c

De plus, si votre fichier contient des colonnes, cela donne un moyen simple de concaténer uniquement certaines colonnes:

# cat > cols.txt
a b c
d e f

# cat cols.txt | awk '{ printf("%s ", $2) }'
b e
ascendants
la source
-1

Sur Red Hat Linux, j'utilise juste echo:

echo $ (cat / un / fichier / nom)

Cela me donne tous les enregistrements d'un fichier sur une seule ligne.

user13498546
la source
2
Cela a déjà été la réponse en 2015. Vous ne faites que dupliquer cette réponse . Veuillez lire les réponses avant de publier les vôtres, spécialement lorsque la question a 7 ans et qu'il y a déjà 8 réponses.
Mickael B.