Come rimuovere \ n tra gli output di due comandi echo?


13

Ho un file di testo contenente un nome file in ogni riga:

111_c4l5r120.png
123_c4l4r60.png
135_c4l4r180.png
147_c4l3r60.png
15_c4l1r120.png
...

Voglio convertirlo in questa forma:

111_c4l5r120.png 111
123_c4l4r60.png 123
135_c4l4r180.png 135
147_c4l3r60.png 147
15_c4l1r120.png 15
...

usando questo codice:

#!/bin/bash
while IFS='' read -r line || [[  -n "$line"  ]]; do
   echo "$line" >> output.txt   
   echo "$line" | cut -d'_' -f 1 >> output.txt
done < "$1"

ma il risultato è:

111_c4l5r120.png 
111
123_c4l4r60.png 
123
135_c4l4r180.png 
135
147_c4l3r60.png 
147
15_c4l1r120.png 
15
...

Come devo cambiare la mia sceneggiatura per ottenere l'output desiderato?


Google trova risultati migliori, ad esempio questo .
Thomas Dickey,

Risposte:


17

A meno che tu non abbia un'esigenza specifica di utilizzare la shell per questo, la risposta di terdon offre alternative migliori.

Dato che stai usando bash(come indicato nello shebang dello script), puoi usare l' -nopzione per fare eco:

echo -n "${line} " >> output.txt
echo "$line" | cut -d'_' -f 1 >> output.txt

Oppure puoi usare le funzionalità della shell per elaborare la linea senza usare cut:

echo "${line} ${line%%_*}" >> output.txt

(sostituendo entrambi echo righe).

In alternativa, printffarebbe anche il trucco, funziona in qualsiasi shell POSIX ed è generalmente migliore (vedere Perché printf è meglio dell'eco? Per i dettagli):

printf "%s " "${line}" >> output.txt
echo "$line" | cut -d'_' -f 1 >> output.txt

o

printf "%s %s\n" "${line}" "${line%%_*}" >> output.txt

(A rigor di termini, in parole povere /bin/sh, echo -nnon è portatile . Dal momento che stai usando esplicitamente bashva bene qui.)


I commenti non sono per una discussione estesa; questa conversazione è stata spostata in chat .
terdon

23

Non fare questo genere di cose nella shell! È molto più complesso del necessario, soggetto a errori e molto, molto più lento. Esistono molti strumenti progettati per tale manipolazione del testo. Ad esempio, in sed(qui assumendo recenti implementazioni GNU o BSD per -E):

$ sed -E 's/([^_]*).*/& \1/' file
111_c4l5r120.png 111
123_c4l4r60.png 123
135_c4l4r180.png 135
147_c4l3r60.png 147
15_c4l1r120.png 15

Oppure, per qualsiasi sed:

$ sed 's/\([^_]*\).*/& \1/' file
111_c4l5r120.png 111
123_c4l4r60.png 123
135_c4l4r180.png 135
147_c4l3r60.png 147
15_c4l1r120.png 15

Perl:

$ perl -pe 's/(.+?)_.*/$& $1/' file
111_c4l5r120.png 111
123_c4l4r60.png 123
135_c4l4r180.png 135
147_c4l3r60.png 147
15_c4l1r120.png 15

awk:

$ awk -F_ '{print $0,$1}' file
111_c4l5r120.png 111
123_c4l4r60.png 123
135_c4l4r180.png 135
147_c4l3r60.png 147
15_c4l1r120.png 15

1
Tuttavia, le utility esterne non sono molto migliori.
EKons

6
@ ΈρικΚωνσταντόπουλος sì, lo sono. Diversi ordini di grandezza più veloci, in realtà. La shell non è molto brava in questo genere di cose. Dopotutto, il lavoro principale di una shell è il lancio di utility esterne. Confronta il tempo impiegato dall'approccio del PO con quello impiegato da una qualsiasi delle soluzioni qui. I loop di shell sono molto, molto lenti. Se hai bisogno di più convincenti, leggi questo .
terdon

In termini di portabilità, no. In termini di velocità, sì. Inoltre, @ StéphaneChazelas è il tuo alias?
EKons

4
@ ΈρικΚωνσταντόπουλος Θα 'θελα :) No, ha appena scritto 2 grandi risposte che erano rilevanti per i due thread dei commenti. Per quanto riguarda la portabilità, con l'eccezione (minore) dell'approccio perl che funzionerà solo su qualcosa come ~ 90% di * macchine nix, tutte e tre le soluzioni sono agnostiche portatili e shell. Oppure, OK, potresti sempre trasformarlo sedin sed 's/\([^_]*\).*/& \1/' fileuna portabilità extra. Il punto è che puoi contare awked sedessere lì più di quanto puoi contare praticamente su qualsiasi altra cosa.
terdon

2

Ecco qui:

#!/bin/bash

while IFS='' read -r line || [[  -n "$line"  ]]; do
   echo "$line" `echo "$line" | cut -d'_' -f 1` >> output.txt
#   echo "$line" | cut -d'_' -f 1 >> output.txt
done < "$1"

Produzione:

$ rm -rf output.txt
$ ./test.sh 1.1; cat output.txt
111_c4l5r120.png 111
123_c4l4r60.png 123
135_c4l4r180.png 135
147_c4l3r60.png 147
15_c4l1r120.png 15
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.