Come rimuovere una nuova riga da una stringa in Bash


110

Ho la seguente variabile.

echo "|$COMMAND|"

che ritorna

|
REBOOT|

Come posso rimuovere quella prima nuova riga?


7
Perché questo è contrassegnato come un duplicato? Questa domanda riguarda la rimozione di un ritorno a capo. La presunta domanda duplicata a cui si collega riguarda la rimozione degli spazi bianchi e menziona solo incidentalmente i ritorni a capo.
Michael Scheper

1
@MichaelScheper ha accettato e riaperto.
fedorqui 'SO smettila di nuocere'

La terminologia qui è strana. Il carattere di terminazione della riga Unix \n(hex 0x0A) è chiamato lie feed (LF); è distinto dal carattere di ritorno a \rcapo (CR) (hex 0x0D) che viene utilizzato su Windows e in molti protocolli di rete come primo byte nella sequenza di fine riga a due byte CR LF.
tripla

Risposte:


114

Sotto , ci sono alcuni bashismi:

Il trcomando potrebbe essere sostituito dal // bashism :

COMMAND=$'\nREBOOT\r   \n'
echo "|${COMMAND}|"
|
   OOT
|

echo "|${COMMAND//[$'\t\r\n']}|"
|REBOOT   |

echo "|${COMMAND//[$'\t\r\n ']}|"
|REBOOT|

Vedi Parameter Expansion e CITAZIONE nella pagina man di bash:

man -Pless\ +/\/pattern bash
man -Pless\ +/\\\'string\\\' bash

man -Pless\ +/^\\\ *Parameter\\\ Exp bash
man -Pless\ +/^\\\ *QUOTING bash

Ulteriore...

Come richiesto da @AlexJordan, questo sopprimerà tutti i caratteri specificati. Quindi cosa succede $COMMANDse contengono spazi ...

COMMAND=$'         \n        RE BOOT      \r           \n'
echo "|$COMMAND|"
|
           BOOT      
|

CLEANED=${COMMAND//[$'\t\r\n']}
echo "|$CLEANED|"
|                 RE BOOT                 |

shopt -q extglob || { echo "Set shell option 'extglob' on.";shopt -s extglob;}

CLEANED=${CLEANED%%*( )}
echo "|$CLEANED|"
|                 RE BOOT|

CLEANED=${CLEANED##*( )}
echo "|$CLEANED|"
|RE BOOT|

In breve:

COMMAND=$'         \n        RE BOOT      \r           \n'
CLEANED=${COMMAND//[$'\t\r\n']} && CLEANED=${CLEANED%%*( )}
echo "|${CLEANED##*( )}|"
|RE BOOT|

Nota: avere l' extglobopzione da abilitare ( shopt -s extglob) per utilizzare la *(...)sintassi.


1
Questo è il modo per rimuovere gli avanzamenti di riga da una variabile in BASH. Altre risposte invocano inutilmente un processo TR aggiuntivo. BTW, ha l'ulteriore vantaggio di rimuovere gli spazi finali!
ingyhere

1
Nota che rimuove anche gli spazi interni da una stringa ... COMMAND="RE BOOT"; echo "|${COMMAND//[$'\t\r\n ']}|"ritorna|REBOOT|
Alex Jordan

2
@AlexJordan Sì, è una caratteristica ricercata : potresti cancellare lo spazio dopo \nper evitare che ciò accada : COMMAND="RE BOOT"; echo "|${COMMAND//[$'\t\r\n']}|"tornerà |RE BOOT|.
F. Hauri

2
Come funziona il pattern ${COMMAND//[$'\t\r\n']}? Pensavo che ${COMMAND//[\t\r\n]}avrebbe semplicemente funzionato, ma non è stato così. A cosa servono il $simbolo e anche le virgolette singole?
haridsv

1
Per quanto riguarda la sintassi $ '', questa è la citazione ANSI C (menzionata nella risposta dei wjordans).
chuckx

81
echo "|$COMMAND|"|tr '\n' ' '

sostituirà la nuova riga (in POSIX / Unix non è un ritorno a capo) con uno spazio.

Ad essere onesto, però, penserei di passare da bash a qualcosa di più sano. O evitare di generare questi dati malformati in primo luogo.

Hmmm, questo sembra che potrebbe essere anche un orribile buco di sicurezza, a seconda della provenienza dei dati.


La data proviene da una richiesta di curl che si trova sullo stesso server, come dovrei metterla in una nuova var? newvar = $ (echo "| $ COMMAND |" | tr '\ n' '')
Matt Leyland

2
Sì. Ma per favore dimmi che non stai permettendo a persone arbitrarie di riavviare il tuo server da remoto senza una password ...
Robin Green

31
Perché non hai usato tr -d '\n'per eliminare invece di sostituire con uno spazio
F. Hauri

3
Per favore, frusta tubi inutili! Utilizzare al tr '\n' ' ' <<< "|$COMMAND|"posto diecho ... | ...
F. Hauri

12
@ F.Hauri: o inutili tr's:"|${COMMAND//$'\n'}|"
rici

75

Pulisci la tua variabile rimuovendo tutti i ritorni a capo:

COMMAND=$(echo $COMMAND|tr -d '\n')

22
Quella striscia non si alimenta? Non dovrebbe essere tr -d '\r'invece?
Izzy

3
L'eco di una variabile non commentata rimuove tutti i caratteri IFS (nuova riga, spazio, tabulazione per impostazione predefinita). Quindi, se hai intenzione di farlo, dovresti essere consapevole che tutti i caratteri IFS vengono eliminati e non hai bisogno del file tr. Semplicemente COMMAND=$(echo $COMMAND)darà un effetto simile. Che è, presumibilmente, la generazione del diavolo poiché invoca un nuovo processo, ma è ancora piuttosto breve e dolce per gli occhi dell'umano e se hai un secondo o due da risparmiare nella tua vita potresti essere disposto a subire il colpo :-).
Mike S

Ho aggiornato la domanda per dire "avanzamento riga", poiché il suo esempio mostrava che era un avanzamento riga, non un ritorno a capo. Questa risposta è ancora corretta, ma forse dovrebbe essere aggiornata per dire "avanzamento riga" invece di "ritorno a capo"?
Benjamin W.

8

Utilizzando bash:

echo "|${COMMAND/$'\n'}|"

(Nota che il carattere di controllo in questa domanda è un 'newline' ( \n), non un ritorno a capo ( \r); quest'ultimo avrebbe output REBOOT|su una singola riga.)

Spiegazione

Utilizza l' espansione dei parametri della shell Bash ${parameter/pattern/string}:

Il pattern viene espanso per produrre un pattern proprio come nell'espansione del nome del file. Il parametro viene espanso e la corrispondenza più lunga del modello rispetto al suo valore viene sostituita con una stringa . [...] Se la stringa è nulla, le corrispondenze del modello vengono eliminate e il modello / seguente può essere omesso.

Utilizza anche il costrutto di $'' citazione ANSI-C per specificare una nuova riga come $'\n'. Anche l'utilizzo diretto di una nuova riga funzionerebbe, anche se meno carino:

echo "|${COMMAND/
}|"

Esempio completo

#!/bin/bash
COMMAND="$'\n'REBOOT"
echo "|${COMMAND/$'\n'}|"
# Outputs |REBOOT|

Oppure, usando le nuove righe:

#!/bin/bash
COMMAND="
REBOOT"
echo "|${COMMAND/
}|"
# Outputs |REBOOT|

6

Quello che ha funzionato per me è stato echo $testVar | tr "\n" " "

Dove testVar conteneva la mia variabile / output di script


4

Aggiunta risposta per mostrare un esempio di rimozione di più caratteri, inclusi \ r l'uso di tr e l'uso di sed. E illustrando l'utilizzo di hexdump.

Nel mio caso avevo scoperto che un comando termina con awk print dell'ultimo elemento |awk '{print $2}' della riga includeva un ritorno a \ r oltre a virgolette.

ero solito sed 's/["\n\r]//g' per rimuovere sia il ritorno a capo che le virgolette.

Potrei anche aver usato tr -d '"\r\n' .

È interessante notare che sed -zè necessario se si desidera rimuovere \ n i caratteri di avanzamento riga.

$ COMMAND=$'\n"REBOOT"\r   \n'

$ echo "$COMMAND" |hexdump -C
00000000  0a 22 52 45 42 4f 4f 54  22 0d 20 20 20 0a 0a     |."REBOOT".   ..|

$ echo "$COMMAND" |tr -d '"\r\n' |hexdump -C
00000000  52 45 42 4f 4f 54 20 20  20                       |REBOOT   |

$ echo "$COMMAND" |sed 's/["\n\r]//g' |hexdump -C
00000000  0a 52 45 42 4f 4f 54 20  20 20 0a 0a              |.REBOOT   ..|

$ echo "$COMMAND" |sed -z 's/["\n\r]//g' |hexdump -C
00000000  52 45 42 4f 4f 54 20 20  20                       |REBOOT   |

E questo è rilevante: cosa sono ritorno a capo, avanzamento riga e avanzamento modulo?

  • CR == \ r == 0x0d
  • LF == \ n == 0x0a

3

Puoi semplicemente usare echo -n "|$COMMAND|".


2

Se stai usando bash con l'opzione extglob abilitata, puoi rimuovere solo lo spazio bianco finale tramite:

shopt -s extglob
COMMAND=$'\nRE BOOT\r   \n'
echo "|${COMMAND%%*([$'\t\r\n '])}|"

Questo produce:

|
RE BOOT|

Oppure sostituisci %% con ## per sostituire solo lo spazio bianco iniziale.


1
Ha funzionato a meraviglia con alcuni strani output che ho ottenuto da un comando docker. Molte grazie!
develCuy
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.