Shell ввода сценариев перенаправления странности

голоса
16

Может кто-нибудь объяснить такое поведение? Бег:

#!/bin/sh
echo hello world | read var1 var2
echo $var1
echo $var2

результаты ни в чем быть вывод, в то время как:

#!/bin/sh
echo hello world > test.file
read var1 var2 < test.file
echo $var1
echo $var2

производит ожидаемый результат:

hello
world

Если не труба сделать один шаг, что перенаправление test.file сделал во втором примере? Я попробовал один и тот же код с обеих тире и Баш снарядов и получил такое же поведение, от них обоих.

Задан 05/08/2008 в 20:26
источник пользователем
На других языках...                            


9 ответов

голоса
11
#!/bin/sh
echo "hello world" | read var1 var2
echo $var1
echo $var2

не производит никакого вывода , поскольку проходят трубопроводы каждого из их компонентов внутри субоболочки. Подоболочки наследуют копию переменных родительской оболочки, а не разделяя их. Попробуй это:

#!/bin/sh
foo="contents of shell variable foo"
echo $foo
(
    echo $foo
    foo="foo contents modified"
    echo $foo
)
echo $foo

Скобки определяют область кода, запускаемую в субоболочке и $ Foo сохраняет свое исходное значение после того, как изменяется внутри них.

Теперь попробуйте это:

#!/bin/sh
foo="contents of shell variable foo"
echo $foo
{
    echo $foo
    foo="foo contents modified"
    echo $foo
}
echo $foo

Скобы являются чисто для группировки, не создается подоболочка и $ Foo модифицирована в фигурных скобках те же $ Foo модифицирована за их пределами.

Теперь попробуйте это:

#!/bin/sh
echo "hello world" | {
    read var1 var2
    echo $var1
    echo $var2
}
echo $var1
echo $var2

Внутри фигурных скобок, чтение встроенное создает $ var1 и $ var2 правильно , и вы можете видеть , что они получают эхо. Вне скобки, они не существуют. Весь код в фигурных скобках была запущена в субоболочке , потому что это один из компонентов трубопровода .

Вы можете поставить произвольное количество кода между фигурными скобками, так что вы можете использовать этот трубопровод, в-а-блочную конструкцию, когда вам нужно запустить блок скрипта, который анализирует выход чего-то другого.

Ответил 19/09/2008 в 03:20
источник пользователем

голоса
9

Это уже ответили правильно, но решение еще не было заявлено. Используйте Ksh, не колотить. Для сравнения:

$ echo 'echo "hello world" | read var1 var2
echo $var1
echo $var2' | bash -s

Для того, чтобы:

$ echo 'echo "hello world" | read var1 var2
echo $var1
echo $var2' | ksh -s
hello
world

КШ является превосходным программированием оболочки из-за маленькие тонкости, как это. (Баш лучше интерактивная оболочка, на мой взгляд.)

Ответил 15/08/2008 в 16:52
источник пользователем

голоса
8

Недавнее дополнение bashявляется lastpipeвариант, который позволяет последней команды в конвейере для запуска в текущей оболочке, а не подоболочки, когда управление заданиями деактивируется.

#!/bin/bash
set +m      # Deactiveate job control
shopt -s lastpipe
echo "hello world" | read var1 var2
echo $var1
echo $var2

будет действительно выход

hello
world
Ответил 26/07/2012 в 13:10
источник пользователем

голоса
8
read var1 var2 < <(echo "hello world")
Ответил 17/09/2008 в 01:17
источник пользователем

голоса
5

Allright, я понял это!

Это трудно ошибка поймать, но результаты от того, как трубы обрабатываются интерпретатором. Каждый элемент трубопровода выполняется в отдельном процессе. Когда наборы команд чтения var1 и var2, это устанавливает них свою собственную подоболочку, а не родительскую оболочку. Таким образом, при выходе из подоболочка, значение var1 и var2 теряется. Можно, однако, попытаться сделать

var1=$(echo "Hello")
echo var1

который возвращает ожидаемый ответ. К сожалению, это работает только для отдельных переменных, вы не можете установить много в то время. Для того, чтобы установить несколько переменных в то время, вы должны либо прочитать в одной переменной и нарезать его на несколько переменных или использовать что-то вроде этого:

set -- $(echo "Hello World")
var1="$1" var2="$2"
echo $var1
echo $var2

Хотя я признаю, что это не так элегантно, как с помощью трубы, она работает. Конечно, вы должны иметь в виду, что читать предназначалось для чтения из файлов в переменные, так что делает его со стандартного ввода должно быть немного сложнее.

Ответил 05/08/2008 в 21:09
источник пользователем

голоса
4

Мое мнение по этому вопросу (с помощью Bash):

read var1 var2 <<< "hello world"
echo $var1 $var2
Ответил 04/03/2009 в 10:52
источник пользователем

голоса
4

Сообщение было правильно ответить, но я хотел бы предложить альтернативный один вкладыш, который, возможно, мог бы быть полезен.

Для присвоения пространства разделенных значений от эха (или стандартный вывода по этому вопросу) в оболочку переменных, вы могли бы рассмотреть вопрос об использовании массивов оболочки:

$ var=( $( echo 'hello world' ) )
$ echo ${var[0]}
hello
$ echo ${var[1]}
world

В этом примере вар представляет собой массив, и содержимое можно получить, используя конструкцию $ {вар [индекс]}, где индекс является индексом массива (начинается с 0).

Таким образом, вы можете иметь столько же параметры, как вы хотите присвоить соответствующий индекс массива.

Ответил 14/09/2008 в 18:00
источник пользователем

голоса
4

Это потому, что версия труба создает подоболочку, который считывает переменную в ее локальном пространстве, а затем уничтожается при выходе из подоболочка.

Выполнить эту команду

$ echo $$;cat | read a
10637

и использовать pstree -p, чтобы посмотреть на запущенных процессах, вы увидите дополнительные оболочки висят от вашей основной оболочки.

    |                       |-bash(10637)-+-bash(10786)
    |                       |             `-cat(10785)
Ответил 05/08/2008 в 21:00
источник пользователем

голоса
3

Пытаться:

echo "hello world" | (read var1 var2 ; echo $var1 ; echo $var2 )

Проблема, как несколько человек заявили, что var1 и var2 создаются в подоболочек среде, которая разрушается, когда это подоболочка выходы. Вышеприведенные избегает разрушающие подоболочку до результата было echo'd. Другим решением является:

result=`echo "hello world"`
read var1 var2 <<EOF
$result
EOF
echo $var1
echo $var2
Ответил 17/09/2008 в 03:15
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more