тимчасове значення скрипта bash по команді


11

Як і команда нижче,

if true; then
   IFS=":" read a b c d e f <<< "$test"

У книзі сказано, що коли команда присвоєння значення ( IFS ":") використовується перед головною командою ( read a b c d e f <<< "$value"), її значення діє тимчасово для основної команди. Отже, readкоманда використовує роздільник :.

Але, як ця команда,

if true; then
   HOME="hello" echo "$HOME"

Ехо-повідомлення не привіт. Яке справжнє значення вищезгаданої команди?

Відповіді:


5

Це зводиться до питання, як працює оцінка. Обидва приклади працюють однаково, проблема трапляється через те, як оболонка (bash, тут) розширює змінні.

Коли ви пишете цю команду:

HOME="foo" echo $HOME

$HOMEРозширюється до команди запуску . Тому воно розширюється до початкового значення, а не до нового, яке ви встановили для команди. HOMEМінлива дійсно були змінені в середовищі , що echoкоманда працює в, однак, ви друкуєте $HOMEвід батька.

Для ілюстрації врахуйте це:

$ HOME="foo" bash -c 'echo $HOME'
foo
$ echo $HOME
/home/terdon

Як видно вище, перша команда друкує тимчасово змінене значення, HOMEа друга друкує оригінал, демонструючи, що змінна була змінена лише тимчасово. Оскільки bash -c ...команда укладена в одинарні лапки ( ' ') замість подвійних ( " "), змінна не розширюється і передається як є новому процесу bash. Потім цей новий процес розширює його і друкує нове значення, на яке він був встановлений. Ви можете бачити це, якщо ви використовуєте set -x:

$ set -x
$ HOME="hello" echo "$HOME"
+ HOME=hello         
+ echo hello
hello

Як ви бачите вище, змінна $HOME ніколи не передається echo. Він бачить лише розширене значення. Порівняти з:

$ HOME="hello" bash -c 'echo $HOME'
+ HOME=hello
+ bash -c 'echo $HOME'
hello

Тут через одиничні лапки змінна, а не її значення передаються новому процесу.


7

Коли оболонка розбирає рядок, вона буде токенізувати рядок на слова, виконувати різні розширення (по порядку) на словах, а потім виконувати команду.

Припустимо test=1:2:3:4:5:6

Давайте розглянемо цю команду: IFS=":" read a b c d e f <<< "$test"

Після токенізації і розширення параметрів відбувається:IFS=":" read a b c d e f <<< "1:2:3:4:5:6"

Оболонка встановить змінну IFS протягом тривалості команди read та readзнає, як застосувати $ IFS до її введення , та дасть значення імен змінних.

Ця команда має схожу історію, але різний результат: HOME="hello" echo "$HOME"

Оскільки розширення параметра відбувається перед початком команди, оболонка має:

HOME="hello" echo "/home/username"

І тоді, під час виконання команди echo, нове значення $ HOME взагалі не використовується.

Щоб досягти того, що ви намагаєтеся зробити, виберіть один із них

# Delay expansion of the variable until its new value is set
HOME="hello" eval 'echo "$HOME"'

або

# Using a subshell, so the altered env variable does not affect the parent.
# The semicolon means that the variable assignment will occur before
# the variable expansion
(HOME="hello"; echo "$HOME")

але не вибирайте перший.


Напевно, краще вибрати перший. Принаймні, це значно швидше. Коли eval - це відповідь, іноді, ймовірно, ви задаєте неправильне запитання. Але якщо хтось повинен зробити це з якихось причин, зміна відповіді не робить саме питання менш помилковим. Ще одне рішення - загорнути його у функцію та використовувати local.
user23013

Чому слід evalуникати рішення?
DarkHeart

Якщо ви не контролюєте строго вхід, ви повинні бути дуже обережними щодо коду, який ви дозволяєте іншим вводити у вашу програму.
glenn jackman

-1

Існує дві сфери: змінні середовища та локальні змінні. Змінні середовища дійсні для кожного процесу (див. setenv, getenv), В той час як локальні змінні активні лише в межах цього сеансу оболонки. (Це не очевидна відмінність ...)

Implied env(як у вашому прикладі) модифікує середовище, тоді як echo ...використовує локальні - тому envне має ефекту.

Для зміни локальних змінних використовуйте, скажімо,

( HOME="foo" ; echo "$HOME" )

Тут круглі дужки визначають обсяг цього призначення.


1
Це не має нічого спільного зі змінною областю, проблема полягає в тому, що змінна розширюється до того, як вона буде передана дочірній оболонці.
тердон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.