Come affermare che una stringa ha un carattere di nuova riga e, in tal caso, rimuoverla


9

Ho una stringa che è il risultato di un'operazione su cui non ho alcun controllo. Quando stampo questa variabile usando echo, ottengo:

echo $myvar
hello

Tuttavia, quando lo faccio

if [ $myvar = "hello" ]; then
    echo they are equal
else
    echo they are not equal
fi

Capisco sempre che non sono uguali. Sospetto che ciò sia dovuto a un newlinepersonaggio.

Anche la stringa si comporta in modo strano. Quando io faccio:

newVAR="this is my var twice: "$myvar$myvar
echo $newVAR

Ottengo:

hellois my var twice: hello

Come posso verificare se ciò è effettivamente dovuto a newlinee, in tal caso, rimuoverlo?


1
In Bash puoi printf '%q\n' "$string"ottenere una versione con escape di qualsiasi stringa. Ad esempio: printf '%q\n' 'foo\n'-> foo\\n; printf '%q\n' $'foo\n'->$'foo\n'
l0b0

1
Non stai citando l'espansione di nessuna delle tue variabili. Se avessero uno spazio bianco finale, non lo vedresti echo $foo. Fare echo "$foo"invece.
Peter Cordes,

Risposte:


9

Il problema è che hai un ritorno a capo (CR, \r) incorporato . Questo fa sì che il punto di inserimento del testo del terminale torni indietro all'inizio della riga che sta stampando. Questo è il motivo per cui stai vedendo il 'ciao' all'inizio della riga nel tuo $newVAResempio - sed -n lmostra una vista leggibile di caratteri non stampabili (e fine della riga).

var=ab$'\r'c ; echo "$var";  printf %s "$var" | sed -n l
# output:
cb
ab\rc$

Puoi provarlo con un semplice controllo delle condizioni bash:

[[ $var == *$'\r'* ]] && echo yes || echo no
# output:
yes

È possibile combinare il test e risolvere in un solo passaggio testando per \r(s) e rimuovendoli tramite:

fix="${var//$'\r'/}"; echo "$var"; echo "$fix"
# output:
cb
abc

La correzione utilizza l' espansione dei parametri della shell . Il particolare modulo usato sopra è per sostituire le sottostringhe in base al modello proposto: ${parameter/pattern/string}<- Sostituisce solo il primo modello trovato con stringa nella variabile denominata * parametro. Per sostituire tutti i pattern, devi solo cambiare il primo /in //.


potresti spiegare il tuo ultimo pezzetto di codice? la fix="....linea?
farid99

@ farid99: spiegazione aggiunta per rispondere, Nota fixpuò essere varse stessa - o spesso puoi semplicemente usare l'espansione del parametro così com'è senza la necessità di riassegnare il valore (possibilmente) modificato ..
Peter.O

5

Puoi rappresentare \rcome $'\r'in bash:

if [ "$myvar" = "hello"$'\r' ]; then
    echo they are equal
else
    echo they are not equal
fi

O tagliare l'ultimo \rin myvar:

if [ "${myvar%$'\r'*}" = "hello" ]; then
    echo they are equal
else
    echo they are not equal
fi

3

Curiosamente, in molte conchiglie getoptsè un candidato molto probabile per un lavoro come questo. All'inizio questo può sembrare controintuitivo, ma se si considera che getoptsla funzione principale è riconoscere e offrire all'interpretazione quante opzioni della riga di comando specificate per singolo carattere si potrebbero trovare in una serie concatenata delle stesse, si potrebbe iniziare a fare un po ' più senso.

Per dimostrare, da una bashshell:

x=$(printf '\n\r%010s\t' hello)
OPTIND=1
while  getopts : na "-$x"
do     printf %q\\n "$OPTARG"
done

$'\n'
$'\r'
\
\
\
\
\
h
e
l
l
o
$'\t'

In tal modo a volte può essere conveniente consentire getoptsdi gestire lo smontaggio come una sorta di pilota automatico della shell per casi come questo. Quando lo fai, puoi semplicemente escludere i byte indesiderati con / caseo [provare ]e creare il backup della stringa dal byte 1:

OPTIND=1 y=$(printf \\n\\r) z=
while  getopts : na "-$x"
do     case $OPTARG in ([!$y])
            z=$z$OPTARG
       esac
done
printf %q\\n "$z"

$'     hello\t'

Dato questo semplice esempio - e data una shell che supporta le espansioni dei parametri già menzionate altrove - le espansioni probabilmente ti serviranno meglio qui. Ma ho pensato getoptsche valesse la pena menzionare anche nel caso in cui non fossi a conoscenza delle sue capacità al riguardo. Certamente quando ne ho saputo ho trovato molte utili applicazioni, comunque.


0

Mentre Bash e altri linguaggi di shell sono utili, a volte è meglio usare un vero linguaggio di scripting, come Perl. Perl può sostituire abbastanza facilmente gli script di shell che chiamano altri linguaggi come sed e awk e i comandi UNIX. L'ho imparato oltre 20 anni fa scrivendo script C-Shell che a loro volta chiamavano sed, awk e vari comandi UNIX - prima di chiamare il codice FORTRAN. In Perl farei:

chomp($myvar);   # removes the newline char

if("$myvar" eq "hello")   # string comparison
  {
  print "they are equal\n";
  }
else
  {
  print "they are not equal\n";
  }
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.