bash - remplace l'espace par une nouvelle ligne

70

Comment puis-je remplacer des espaces par de nouvelles lignes sur une entrée comme:

/path/to/file /path/to/file2 /path/to/file3 /path/to/file4 /path/to/file5 etc...

Pour obtenir ce qui suit:

/path/to/file
/path/to/file2
/path/to/file3
/path/to/file4
/path/to/file5

Remarque

Je poste cette question pour aider les autres utilisateurs, il n’était pas facile de trouver une réponse utile sous UNIX SE jusqu’à ce que je commence à taper cette question. Après cela, j'ai trouvé ce qui suit:

Question connexe

Comment puis-je trouver et remplacer par une nouvelle ligne?

laconbass
la source
ls / chemin / vers / | xargs echo | sed 's / \ s \ + / \ n / g'
SD.

Réponses:

125

Utilisez la trcommande

echo "/path/to/file /path/to/file2 /path/to/file3 /path/to/file4 /path/to/file5"\
| tr " " "\n"

Trouvé sur http://www.unix.com/shell-programming-scripting/67831-replace-space-new-line.html

laconbass
la source
1
C'était aussi ma première pensée, bien qu'il y ait tellement de façons de le faire! C’est à peu près EXACTEMENT ce trqu’il faut faire!
Rob
5
+1, mais comme commentaire: Cela ne fonctionne pas si les noms de fichiers contiennent des espaces eux
Bonsi Scott
20

Dans ce cas, j'utiliserais printf:

printf '%s\n' /path/to/file /path/to/file2 /path/to/file3 /path/to/file4 /path/to/file5

S'il y a des espaces dans l'un des chemins, vous pouvez citer ce chemin de fichier afin d'éviter sa division sur les espaces:

printf '%s\n' /path/to/file '/path/to/file with spaces' /path/to/another/file

Pour transformer du texte en général, trvotre meilleur choix est celui décrit dans une réponse existante.

vilsoup
la source
1
Petit mot du futur: merci d’avoir posté cette solution, c’est très fiable pour moi, comparé à "echo".
Liesmith
5

En supposant que vous ayez une chaîne avec des espaces comme séparateurs:

newline_separated=${space_separated// /$'\n'}

Cependant, vous posez probablement la mauvaise question. (Pas nécessairement, par exemple, cela pourrait apparaître dans un fichier makefile.) Une liste de noms de fichiers séparés par des espaces ne fonctionne pas vraiment: que se passe-t-il si l'un des noms de fichiers contient des espaces?

Si un programme reçoit des noms de fichiers sous forme d'arguments, ne les associez pas à des espaces. Utilisez "$@"pour y accéder un par un. Bien que echo "$@"les arguments soient séparés par des espaces, cela est dû à echo: il affiche ses arguments avec des espaces comme séparateurs. somecommand "$@"transmet les noms de fichiers sous forme d'arguments distincts à la commande. Si vous souhaitez imprimer les arguments sur des lignes séparées, vous pouvez utiliser

printf '%s\n' "$@"

Si vous avez des noms de fichiers séparés par des espaces et que vous souhaitez les utiliser dans un tableau, vous pouvez utiliser un développement de variable non entre guillemets pour scinder la valeur en caractères IFS(vous devez désactiver le développement de caractères génériques set -f, sinon glob les motifs seront étendus dans la valeur):

space_separated_list='/path/to/file1 /path/to/file2 /path/to/file3'
IFS=' '; set -f
eval "array=(\$space_separated_list)"
for x in "${array[@]}"; do 

Vous pouvez encapsuler ceci dans une fonction qui restaure le -fréglage et la valeur IFSquand c'est fait:

split_list () {
  local IFS=' ' flags='+f'
  if [[ $- = *f* ]]; then flags=; fi
  set -f
  eval "$1=($2)"
  set $flags
}
split_list array '/path/to/file1 /path/to/file2 /path/to/file3'
for x in "${array[@]}"; do 
Gilles, arrête de faire le mal
la source
Changer la bonne réponse à celle-ci. Je pense qu'il est plus correct de rechercher comment je suis parvenu à une liste séparée par des espaces et de récupérer cette information d'une autre manière. Ce serait bien pour les apprenants comme moi si vous commentiez un peu votre réseau, en nous disant ce que font des choses comme le var IFS local ou la condition $ - = f . Ce genre de choses qu'une personne qui utilise bash quelques fois ne sait pas.
laconbass
@laconbass J'ai ajouté une brève explication. Recherchez set -fet IFSdans le manuel bash si vous voulez tous les détails. Voir aussi unix.stackexchange.com/questions/16192/…
Gilles 'arrête d'être méchant'
@Guilles Cette courte explication me suffit et je pense que ce le sera pour beaucoup d’autres. Ty pour votre temps
laconbass
paramètre IFSlocal ne prend pas effet
Eliran Malka
@ EliranMalka Je n'ai aucune idée de ce que vous entendez par là. Si un script ne se comporte pas comme vous le pensez, vous pouvez poser une question ici.
Gilles 'SO- arrête d'être méchant'
4

Soyez pragmatique, utilisez sed !!

sed 's/\s\+/\n/g' file

Ce qui précède dit de remplacer un ou plusieurs caractères d'espacement (\ s +) par une nouvelle ligne (\ n)

C'est plus ou moins:

'substitute /one space or more/ for /newline/ globally'
MGP
la source
1
remplacer le changement par le substitut, c'est ce que le s signifie réellement!
Rob
@Rob merci, n'oubliez pas que vous pouvez modifier les réponses des autres.
MGP
1
Si vous avez plusieurs espaces entre les textes, vous obtiendrez des lignes vides. Vous devez ajouter un '+' après le \ s pour indiquer que vous souhaitez faire correspondre au moins un espace, par rapport à un seul espace. c'est à dire. sed 's / \ s + / \ n / g'
DarkHeart
4

Au lieu trde @laconbass, vous pouvez également utiliser xargsdans ce cas:

echo "/path/to/file /path/to/file2 /path/to/file3 /path/to/file4  /path/to/file5"\
| xargs -n1

L'avantage est que cela fonctionne même avec plusieurs espaces, ce qui trn'est pas le cas.

FranMowinckel
la source
0

Voici comment je l'ai fait:

echo "/path/to/file /path/to/file2 /path/to/file3 /path/to/file4 /path/to/file5" | sed 's/ /\
'/g

Notez l'utilisation de la touche Entrée après la barre oblique inverse dans la sedcommande.

unxnut
la source
ce Prons et le contre a sedplus tr?
laconbass
Votre niveau de confort :-) Je pense que vous pouvez en faire plus sedcar c'est un éditeur plutôt que de simplement traduire des caractères.
unxnut
4
sedpeut faire tellement plus, mais est totalement excessive pour cela. trC’est le bon outil pour CE métier, mais la connaissance de sedregex sera utile plus tard!
Rob
0

Une autre approche, en supposant que la ligne se trouve dans une variable appelée line:

for path in $line;do echo $path;done

Ceci utilise le fait que Bash divise ses arguments sur les espaces par défaut et qu’il echoajoute une nouvelle ligne à son entrée par défaut.

Joseph R.
la source
J'ai essayé ceci sur mon système Ubuntu avant de poster cette question et je ne pouvais pas le faire fonctionner.
laconbass
0
echo word1 word2 ... | sed -e 'y/ /\n/;P;D'

est une autre méthode pour transformer des mots séparés par un espace en virgules séparées.


la source
-1

Le script suivant est facile à comprendre et à utiliser.

cat filename | tr ' ' '\n' | tee filename
sanjeev kanabargi
la source
2
L’essence de votre réponse ( tr) est la même que dans la réponse acceptée. A côté de cela, votre réponse présente les problèmes suivants: a) la commande n'est pas indentée de 4 espaces (-> disposition de démarquage) b) votre utilisation de catest inutile (vous pouvez la remplacer par < filename tr ' ' '\n'). c) Votre nom de fichier de sortie est le même que le nom de fichier d'entrée. Avec cela, vous créez une course de données.
maxschlepzig
1
En dehors de l'analyse correcte de maxschlepzig, il ne s'agit pas d'un script, mais d'un ensemble de commandes connectées dont le nom est codé en dur (le script aurait un en-tête spécifiant le shell à utiliser et deux paramètres pour spécifier l'entrée et la sortie). En dehors de cela, 2 personnes sur 3 dans mon ménage ne trouvent pas cela facile à comprendre. Peut-être que ce n’est pas représentatif, mais gardez à l’esprit que quelque chose que vous comprenez vous-même (ou dans ce cas pensez que vous comprenez) semble toujours facile.
Anthon