bash - reemplaza el espacio con una nueva línea


70

¿Cómo puedo reemplazar espacios con nuevas líneas en una entrada como:

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

Para obtener lo siguiente:

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

Nota

Estoy publicando esta pregunta para ayudar a otros usuarios, no fue fácil encontrar una respuesta útil en UNIX SE hasta que comencé a escribir esta pregunta. Después de eso encontré lo siguiente:

Pregunta relacionada

¿Cómo puedo encontrar y reemplazar con una nueva línea?



ls / ruta / a / | xargs echo | sed 's / \ s \ + / \ n / g'
SD.

Respuestas:



20

En este caso, usaría printf:

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

Si hay espacios dentro de una de las rutas, puede citar esa ruta de archivo para evitar que se divida en los espacios:

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

Para transformar el texto en general, tres su mejor apuesta, como se cubre en una respuesta existente.


1
Una nota rápida del futuro: gracias por publicar esta solución, ha sido muy confiable para mí, en comparación con el uso de "echo".
Liesmith

5

Suponiendo que tiene una cadena con espacios como separadores:

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

Sin embargo, probablemente estés haciendo la pregunta equivocada. (No necesariamente, por ejemplo, esto podría aparecer en un archivo MAKE). Una lista de nombres de archivos separados por espacios no funciona realmente: ¿qué pasa si uno de los nombres de archivo contiene espacios?

Si un programa recibe nombres de archivo como argumentos, no los una con espacios. Use "$@"para acceder a ellos uno por uno. Aunque echo "$@"imprime los argumentos con espacios intermedios, eso se debe a echo: imprime sus argumentos con espacios como separadores. somecommand "$@"pasa los nombres de archivo como argumentos separados al comando. Si desea imprimir los argumentos en líneas separadas, puede usar

printf '%s\n' "$@"

Si tiene nombres de archivo separados por espacios y desea colocarlos en una matriz para trabajar en ellos, puede usar una expansión de variable sin comillas para dividir el valor en los caracteres IFS(necesitará deshabilitar la expansión de comodín con set -f, de lo contrario, glob los patrones se expandirán en el valor):

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 

Puede encapsular esto en una función que restaura la -fconfiguración y el valor de IFScuando se hace:

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 

Cambiar la respuesta correcta a esta. Creo que es más correcto investigar cómo llegué a una lista separada por espacios y recuperar esa información de otra manera. Sería genial para los estudiantes como yo si comentas un poco tu snipnet, diciéndonos qué hacen las cosas como el var IFS local o la condición $ - = f do. Ese tipo de cosas que una persona que usa bash pocas veces no sabe.
laconbass

@laconbass He agregado una breve explicación. Mire hacia arriba set -fy IFSen el manual de bash si desea todos los detalles. Ver también unix.stackexchange.com/questions/16192/…
Gilles 'SO- deja de ser malvado'

@Guilles Esa breve explicación es suficiente para mí, y creo que será para muchos otros. Ty por su tiempo
laconbass

configuración IFSlocal no surte efecto
Eliran Malka

@EliranMalka No tengo idea de lo que quieres decir con esto. Si un script no se comporta de la manera que usted cree que debería, puede hacer una pregunta aquí.
Gilles 'SO- deja de ser malvado'

4

Se pragmático, usa sed !!

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

Lo anterior dice que sustituya uno o más caracteres de espacio en blanco (\ s +) con nueva línea (\ n)

Esto es más o menos:

'substitute /one space or more/ for /newline/ globally'

1
reemplace el cambio con un sustituto, ¡eso es lo que realmente significa!
Rob

@ Rob gracias, recuerda que puedes editar otras respuestas.
Pop

1
Si tiene varios espacios entre el texto, obtendrá líneas en blanco. Debe agregar un '+' después de \ s para indicar que desea hacer coincidir al menos uno de los espacios, exactamente como corresponde a un espacio. es decir. sed 's / \ s + / \ n / g'
DarkHeart

4

Como alternativa a tr@laconbass, también puede usar xargsen este caso:

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

La ventaja es que funciona incluso con espacios en blanco múltiples, lo trque no funciona.


0

Así es como lo hice:

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

Observe el uso de la tecla Intro después de la barra diagonal inversa en el sedcomando.


¿Qué prons y contras ha sedterminado tr?
laconbass

Su nivel de comodidad :-) Creo que puede hacer más, sedya que es un editor en lugar de simplemente traducir caracteres.
unxnut

44
sedpuede hacer mucho más, pero es totalmente excesivo para esto. tres la herramienta adecuada para ESTE trabajo, ¡pero el conocimiento sedy las expresiones regulares serán útiles más adelante!
Rob

0

Otro enfoque, suponiendo que la línea está en una variable llamada line:

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

Esto hace uso del hecho de que Bash divide sus argumentos en espacios en blanco de forma predeterminada y que echoagrega una nueva línea a su entrada de forma predeterminada.


Intenté esto en mi sistema ubuntu antes de publicar esta pregunta y no pude hacerlo funcionar.
laconbass

0
echo word1 word2 ... | sed -e 'y/ /\n/;P;D'

es otro método para convertir palabras separadas por un solo espacio en una nueva línea separada.


-1

El siguiente script es fácil de entender y fácil de usar.

cat filename | tr ' ' '\n' | tee filename

2
La esencia de su respuesta ( tr) es la misma que en la respuesta aceptada. Además de que su respuesta tiene los siguientes problemas: a) el comando no está sangrado con 4 espacios (-> diseño de reducción) b) Su uso de cates inútil (puede reemplazarlo por < filename tr ' ' '\n'). c) Su nombre de archivo de salida es el mismo que el nombre de archivo de entrada. Con eso creas una carrera de datos.
maxschlepzig

1
aparte del análisis correcto de maxschlepzig, este no es un script, sino un conjunto de comandos conectados que tienen un nombre codificado (como se espera que el script tenga un encabezado que especifique el shell para usar y use dos parámetros para especificar y generar). Aparte de eso, 2 de cada 3 personas en mi hogar no lo encuentran fácil de entender. Tal vez eso no sea representativo, pero tenga en cuenta que algo que usted mismo comprende (o en este caso cree que comprende) siempre parece fácil.
Anthon
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.