bash: assegnazione della prima riga di una variabile a una variabile


11

Ho una variabile multilinea e voglio solo la prima riga in quella variabile. Il seguente script dimostra il problema:

#!/bin/bash

STRINGTEST="Onlygetthefirstline
butnotthesecond
orthethird"

echo "  Take the first line and send to standard output:"
echo ${STRINGTEST%%$'\n'*}
#   Output is as follows:
# Onlygetthefirstline

echo "  Set the value of the variable to the first line of the variable:"
STRINGTEST=${STRINGTEST%%$'\n'*}

echo "  Send the modified variable to standard output:"
echo $STRINGTEST
#   Output is as follows:
# Onlygetthefirstline butnotthesecond orthethird

Domanda: Perché ${STRINGTEST%%$'\n'*}restituisce la prima riga quando viene posizionata dopo un echocomando, ma sostituisce le nuove righe con spazi quando viene posizionata dopo l'assegnazione?


1
Impossibile riprodurlo. Funziona per me come previsto.
Peque,

1
Non è possibile riprodurre neanche con 2.05b, 3.1, 3.2, 4.0, 4.1, 4.2, 4.3. Sembra un errore dell'utente come provare a eseguirlo con una shell che non supporta $'...'invece di bash.
Stéphane Chazelas,

Risposte:


8

Forse c'è un altro modo per archiviare ciò che vuoi fare, ma funziona

#!/bin/bash

STRINGTEST="
Onlygetthefirstline
butnotthesecond
orthethird
"

STRINGTEST=(${STRINGTEST[@]})
echo "${STRINGTEST[0]}"

Ciò presuppone che le righe in $STRINGTESTnon contengano spazi vuoti o caratteri jolly. Si noti inoltre che le righe vuote (come nella prima riga di quella variabile) vengono ignorate.
Stéphane Chazelas,

3
Si noti inoltre che l'utilizzo STRINGTEST=(${STRINGTEST[@]})ha poco senso ed è equivalente a STRINGTEST=($STRINGTEST)poiché STRINGTESTprecedentemente era definito come una variabile scalare (non array ).
Stéphane Chazelas,

10

potrebbe non essere più efficiente ma una fodera ...

firstLine=`echo "${multiLineVariable}" | head -1`

2
Mi piace per chiarezza e brevità.
Peter - Ripristina Monica il

Questo firstLine=`echo "${test_var}" | sed -n 1pfunziona anche se si dispone di una ragione per usare sed invece (ad esempio, significa che è possibile eseguire contemporaneamente una sostituzione alla linea: echo "${test_var}" | sed -nE '1 s/# *(.*)/\1/p'.
robenkleene

7

Quel codice funziona per me con tutte le versioni di bash che ho provato tra 2.05b e 4.3. Più probabilmente hai provato a eseguire quello script con una shell diversa che non supporta la $'...'forma di quotazione.

Che $'...'la sintassi non è standard shsintassi (ancora) e supportato solo (come del 2015/05/22 e per quanto ne so) di ksh93(dove è nato), zsh, bash, le versioni recenti di mkshe le sho recenti versioni di FreeBSD .

La mia scommessa è che si è tentato di eseguire lo script con il shposto di bashe il vostro shè basata sulle versioni di ash, pdksh, yasho ksh88che non supportano ancora.

Se vuoi rendere compatibile quel codice POSIX 2008, dovresti scriverlo:

STRINGTEST="Onlygetthefirstline
butnotthesecond
orthethird"

NL='
'
STRINGTEST=${STRINGTEST%%"$NL"*}
printf '%s\n' "$STRINGTEST"

Quindi, puoi farlo interpretare da qualsiasi shell conforme a POSIX basho da quelle più snelle / veloci come la tua sh.

(e ricorda che lasciare una variabile non quotata nel contesto dell'elenco ha un significato molto speciale nelle shell tipo Bourne).


O potrebbe essere una versione precedente di bash. Potrei riprodurre il comportamento con 2.03.
Gilles 'SO- smetti di essere malvagio'

@Gilles, l'ultimo sistema operativo supportato che includeva bash-2.03 (rilasciato 16 anni fa) era probabilmente Solaris 8 che è diventato EOL oltre 3 anni fa. Questa ipotesi sembra abbastanza improbabile.
Stéphane Chazelas,

1

Questo funziona per me:

STRINGTEST="Some Text 1
Some Text 2
Some Text 3"

readarray -t lines < <(echo "$STRINGTEST")
echo "${lines[0]}"

E funziona anche per le righe vuote:

STRINGTEST="
Some Text 1
Some Text 2
Some Text 3"

readarray -t lines < <(echo "$STRINGTEST")
echo "${lines[0]}"

Se ci si preoccupa di avviare la sostituzione del processo, si potrebbe anche semplicemente readuna volta in una semplice variabile (invece di readarrayindicizzare più).
Peter - Ripristina Monica il

0

Con Bash integrato reade qui-stringa:

#!/usr/bin/env bash

STRINGTEST="
Some Text 1
Some Text 2
Some Text 3"


IFS=$'\n' read -r STRINGTEST <<<"$STRINGTEST"

Utilizzando l'espansione dei parametri POSIX:

#!/usr/bin/env sh

STRINGTEST="
Some Text 1
Some Text 2
Some Text 3"

# Disables globing
set -f

# Field separator is newline only
IFS="
"

# No quotes, split lines as arguments because of IFS
set -- $STRINGTEST

# First argument is first line
STRINGTEST="$1"
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.