Почему я должен помещать команду read в подоболочку при использовании конвейера

tl;dr используйте exec $SHELL, если вы хотите запустить ту же оболочку, в которой вы находитесь. Принятый ответ будет работать только для вас, если вы используете bash.

--

Принятый ответ отлично подходит для оболочки, использующей bash, о чем также спрашивал ОП, однако я использую терминал в macOS с оболочкой по умолчанию, отличной от -(zsh ), и запускаю команда exec bashявно не дает желаемого эффекта :она запускает bash вместо моей оболочки по умолчанию.

Таким образом, независимой от среды -командой будет exec $SHELL, которая использует переменную среды $SHELL, в которой хранится оболочка по умолчанию для пользователя.

Кроме того, обратите внимание, что Apple заменила bash на zsh в macOS Catalina, поэтому после обновления до macOS 10.15 можно добиться эффекта, который ищет OP для запуска exec zshили exec $SHELL.

5
01.12.2020, 04:58
2 ответа

Альтернативой является использование замены процесса:

{ read header; read filesystem rest; } < <(df.)
echo "$filesystem"

Подстановка процесса <(...)выполняет содержащийся сценарий (в подоболочке ), но он действует как имя файла, поэтому вам нужен первый <для перенаправления содержимого (, которое является выходом сценарий )в скобках. Сгруппированные команды выполняются в текущей оболочке.

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

{
    read header
    read filesystem rest
} < <(
    df.
)
echo "$filesystem"

Возможно, будет проще использовать внешний инструмент для извлечения файловой системы:

filesystem=$( df. | awk 'NR == 2 {print $1}' )
3
18.03.2021, 22:46

Ваша первая команда

df. | read a; read a b; echo "$a"

эффективно интерпретируется как

( df. | read a ) ; read a b; echo "$a"

Таким образом, конвейер работает только с командой read a.

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

Теперь это не обязательно должна быть подоболочка; это может быть группировка..

bash-4.2$ df | { read a ; read a b ; echo $a ; }
devtmpfs

Чаще всего вам может понадобиться петля

bash-4.2$ df | while read a
> do
> read a b
> echo $a
> done
devtmpfs
tmpfs
/dev/vda3
/dev/vdb

Существует второстепенная проблема с bashи правой стороной конвейера, запускаемой подоболочкой, поэтому значения$a$bнедоступны вне цикла while, но это другая проблема!

2
18.03.2021, 22:46

Теги

Похожие вопросы