Ubicación y contenido del file de salida según la list de files

Tengo un file que contiene ubicaciones de diferentes files llamados locationfile.txt que contiene:

 /home/user/documents/file1 /home/user/file2 /home/user/file3 

Cada file de text tiene alnetworkingedor de 10 líneas y quiero enviar todos los files a otro file llamado file finalfile .

Me di count de que si lo hago

 cat locationfile.txt | while read line; do cat "$line"; done 

Esto imprime todos los files juntos para que se convierta en un file de text de ~ 30 líneas.

Cuál es mi pregunta, cómo puedo escupir ese file poner include las ubicaciones de files entre el text como este:

 /home/user/documents/file1 text text text "" /home/user/file2 text text text "" /home/user/file3 text text text "" 

Antes de que el cat haga un echo o printf del nombre del file:

 while read line; do printf '%s\n' "$line"; cat "$line"; done <locationfile.txt >finalfile 

O, más legible:

 while read line; do printf '%s\n' "$line" cat "$line" done <locationfile.txt >finalfile 

Tenga en count que esto requiere que todas las routes en locationfile.txt no tengan \ en ellas.

Si bien tener \ en los nombres de las routes es muy inusual, sería más seguro hacerlo

 while read -r line; do printf '%s\n' "$line" cat "$line" done <locationfile.txt >finalfile 

… que no tiene las mismas restricciones.

Agregue una marca de verificación para asegurarse de que el file realmente exista también y generando una advertencia si no lo hace:

 while read -r line; do if [[ -f "$line" ]]; then printf '%s\n' "$line" cat "$line" else printf 'Warning: "%s" does not exist\n' "$line" >&2 fi done <locationfile.txt >finalfile 

"No existe" aquí significa "al less no es un file normal".

Si quieres el "" allí también, como una especie de marcador de contenido de final de file, simplemente ponlo después de cat :

 while read -r line; do if [[ -f "$line" ]]; then printf '%s\n' "$line" cat "$line" echo '""' else printf 'Warning: "%s" does not exist\n' "$line" >&2 fi done <locationfile.txt >finalfile 

Y, por último, dar nombres que se auto-documentan:

 while read -r file_path; do if [[ -f "$file_path" ]]; then printf '%s\n' "$file_path" cat "$file_path" echo '""' else printf 'Warning: "%s" does not exist\n' "$file_path" >&2 fi done <file_paths.txt >files_concat_with_paths.txt 
 while read file; do ( echo "$file"; cat "$file"; echo '"""' ) >> /path/to/outputfile done < /path/to/filelist 

Aquí hay una opción si tiene GNU awk, que evita los loops de shell por completo:

 xargs -d '\n' -a locationfile.txt gawk 'BEGINFILE{print FILENAME} 1' > newfile 

o con GNU sed:

 xargs -d '\n' -a locationfile.txt sed -s '1F' > newfile 

Si no te importa el formatting exacto de los nombres de los files, puedes usar este truco con la head :

 xargs -d '\n' -a locationfile.txt head -vn -0 > newfile 

(el -n -0 le dice a la head que muestre todas las líneas excepto el primer 0, es decir, todas las líneas).

Otro enfoque de Perl:

 $ perl -le 'do{print $_,`cat $_`,"\"\"";} for <>' locationfile.txt text text text "" text text text "" text text text "" 

Eso es usar un poco de magia Perl y podría necesitar una explicación. El -l elimina las nuevas líneas finales de cada línea de input y agrega una línea nueva a cada llamada de print . El -e es como le das un guion a perl .

Ahora, <> es "el contenido del file de input dividido en una matriz". Entonces, do {foo} for <> ejecutará foo en cada línea del file de input. Dentro de ese ciclo for , la variable especial $_ se asigna a cada línea de input. La syntax `command` ejecutará el command en el shell pnetworkingeterminado (una llamada al sistema) y devolverá su salida. Entonces, cat $_ cat cada nombre de file en locationfile.txt .

En total, print $_,`cat $_`,"\"\"" imprimirá el nombre del file (actualmente en $_ ), el resultado del cat (el contenido del file) y luego "" (pero tenemos que escaping) esos, entonces \"\" ).

En otras palabras, esa secuencia de commands significa "leer cada línea de input, imprimirla, cat el file que contiene e imprimir un "" después de cada file.

Solo puede agregar echo "$line" a su ciclo:

 cat locationfile.txt | while read line; do echo "$line" && cat "$line"; done 

Enfoque AWK a través de la function system() . Creamos la cadena de commands a través de sprintf y la pasamos al system()

 $ awk '{print $0; cmd=sprintf("cat \"%s\"",$0);system(cmd); print "\"\""}' filenames.txt /home/xieerqi/input1.txt Hello, I am input file #1 And this is second line of the text "" /home/xieerqi/input2.txt And I am input file #2 Roses are networking, violets are blue AWK is awesome, Python is too "" /etc/resolv.conf # Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8) # DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN nameserver 127.0.1.1 "" 

Y enfoque de Perl, pero con abrir el file dentro del código:

 $ perl -ne 'chomp; open($fh,$_) or die;print "$_\n";while($line = <$fh>){ print $line; print "\"\"\n" if eof}' filenames> /home/xieerqi/input1.txt Hello, I am input file #1 And this is second line of the text "" /home/xieerqi/input2.txt And I am input file #2 Roses are networking, violets are blue AWK is awesome, Python is too "" /etc/resolv.conf # Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8) # DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN nameserver 127.0.1.1 ""