bash: Присвоєння першого рядка змінної змінній


11

У мене є багаторядкова змінна, і я хочу лише перший рядок у цій змінній. Наступний сценарій демонструє проблему:

#!/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

Запитання: Чому ${STRINGTEST%%$'\n'*}повертається перший рядок, коли він розміщений після echoкоманди, але замінює нові рядки пробілами, коли розміщується після призначення?


1
Неможливо відтворити його. Це працює для мене, як очікувалося.
Пеке

1
Неможливо відтворити будь-який із 2.05b, 3.1, 3.2, 4.0, 4.1, 4.2, 4.3. Здається, що помилка користувача, як намагання запустити його з оболонкою, яка не підтримує $'...'замість bash.
Стефан Шазелас

Відповіді:


8

Можливо, є інший спосіб архівувати те, що ви хочете зробити, але це працює

#!/bin/bash

STRINGTEST="
Onlygetthefirstline
butnotthesecond
orthethird
"

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

Це передбачає, що рядки $STRINGTESTне містять пробілів або символів. Також зауважте, що порожні рядки (як і в першому рядку цієї змінної) ігноруються.
Стефан Шазелас

3
Також зауважте, що використання STRINGTEST=(${STRINGTEST[@]})має мало сенсу та еквівалентно STRINGTEST=($STRINGTEST)тому, що STRINGTESTраніше було визначено як скалярну (не масивну ) змінну.
Стефан Шазелас

10

може бути не найефективнішим, але один вкладиш ...

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

2
Мені це подобається за ясність і стислість.
Пітер - Відновіть Моніку

Це firstLine=`echo "${test_var}" | sed -n 1pтакож працює , якщо у вас є причини для використання СЕД замість (наприклад, це означає , що ви можете одночасно виконати заміну лінії: echo "${test_var}" | sed -nE '1 s/# *(.*)/\1/p'.
robenkleene

7

Цей код працює для мене з усіма версіями bash, які я пробував між 2.05b та 4.3. Швидше за все, ви намагалися запустити цей скрипт з іншою оболонкою, яка не підтримує $'...'форму цитування.

Цей $'...'синтаксис не є стандартним shсинтаксисом (поки) і підтримується тільки (за станом на 2015-05-22 й AFAIK) шляхом ksh93(де вона виникла), zsh, bash, останні версії mkshі shчи в останніх версіях FreeBSD .

Моя ставка буде то , що ви намагалися запустити цей скрипт з shзамість bashі ваш shзаснований на версії ash, pdksh, yashабо ksh88які не підтримують його ще.

Якщо ви хочете зробити цей код POSIX 2008 сумісним, вам потрібно буде написати його:

STRINGTEST="Onlygetthefirstline
butnotthesecond
orthethird"

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

Тоді ви можете інтерпретувати його будь-якою оболонкою, сумісною з POSIX, bashабо будь-якою швидшою / швидшою, як ваша sh.

(і пам’ятайте, що залишення змінної без цитування в контексті списку має дуже особливе значення в оболонках Борна).


Або це може бути старша версія bash. Я міг відтворити поведінку з 2.03.
Жиль «ТАК - перестань бути злим»

@Gilles, остання підтримувана ОС, яка включала bash-2.03 (випущена 16 років тому), ймовірно, була Solaris 8, яка вийшла EOL більше 3 років тому. Ця гіпотеза здається досить малоймовірною.
Стефан Шазелас

1

Це працює для мене:

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

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

А також це працює для порожніх рядків:

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

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

Якщо хтось заважає запустити процес заміщення, то можна просто readодин раз перетворитись у просту змінну (замість readarrayплюс індексувати).
Пітер - Відновіть Моніку

0

За допомогою вбудованого Bash readі тут-string:

#!/usr/bin/env bash

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


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

Використання розширення параметрів 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"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.