LoginSignup
8
6

More than 3 years have passed since last update.

ShellScript: zsh: パイプからの入力を変数へ代入する(右方向への代入).

Last updated at Posted at 2020-06-06

要約

  • 右方向への代入の代表的な方法は以下である.
zsh限定
echo 'abc' | read -d '' x
Mac限定.pbcopyを用いた場合
echo 'abc' | pbcopy
x=$(pbpaste)

追記2021/04/05
Bashに関しては以下
Bash: パイプからの入力を変数へ代入する(右方向への代入). - Qiita, https://qiita.com/BlackCat_617/items/2b3003c4bb79b5d89bc8

はじめに

 多くのプログラミング言語において変数への代入(assign)は,等号記号=を挟んで右辺の値を左辺の変数へと代入する.
 ShellScriptはパイプ|でコマンド群を繋ぐことでデータが処理され,左から右へとデータが流れていく.その結果を変数へ納めたいときは,コマンド置換(command substitution,$(command))を用い,右辺のコマンド置換を左辺の変数へと代入する.すなわち,パイプラインは左から右へと流れるが,変数代入は右から左へと流れ,「視線と意識の向きが逆流」[1]する.それがなんとなく気持ち悪く感ずる人は少なからずいるようである[2].解決策は[2]の通りであるが,あまり取り上げられない話題で,便利な技術なのでここであらためて取り上げることにした.

環境

  • macOS: 10.15.4
  • zsh: 5.7.1
  • bash: 5.0.17

準備

Bashのreadコマンドではうまくいかない.

  • パイプから入力を受けて変数に代入するコマンドreadが使えそうである.
  • しかし,以下ではabcを変数xに代入しても,取り出すことができない[3].
  • パイプラインで繋がれた各コマンドはそれぞれサブシェルで実行されることが理由のようである[5].(Bash Reference Manual - 3.2.2 Pipelines, https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Pipelines ).

Each command in a pipeline is executed in its own subshell (see Command Execution Environment).

bashではreadを用いてもうまくいかない.
$ echo 'abc' | read x ;  echo $x
$        # xへの代入はサブシェルで実行されたため,メインシェルで取り出せない.

パイプからの入力を変数に代入(右方向代入)

zshを用いる.

  • zshと他のshell(bash 他)との(かなり大きな)違いの一つに,パイプラインの扱いがある.
  • 前述のように,例えばbashでは,パイプで繋がれたコマンドはサブシェルで実行される.
  • しかし,zshにおいては,最後のパイプで繋がれたコマンドはメインシェルで実行される!!(zsh - Main differences from bash | zsh Tutorial[4]).
  • 従って,最後のパイプを変数で受けると,その変数をメインシェル内で使える.
zshではreadを用いてうまくいく.
echo 'abc' | read x ;  echo $x
abc   # 結果.xに格納された値を取り出せている.

複数行の標準入力をパイプから変数で受ける.

  • readで読む際の区切り文字は指定なしの場合は改行[6]で,そのため複数行が入力された場合,1行目しか読んでくれない.
  • オプション-dで区切り文字をなし''とすると,文字列の最後まで読んでくれる.
オプション-dなし
echo 'abc\nefg' | read x ;  echo $x      
abc     #1行目までしか読んでくれない.
-dで''を指定.
echo 'abc\nefg' | read -d '' x ;  echo $x
abc  
efg   # 結果.文字列の最後まで読んでくれる.

その他の右方代入の方法

pbcopyを用いた方法(Mac限定)

  • MacOSのシェルにはMac固有コマンドがある.
  • 固有コマンドの一つにpbcopy(とpbpaste)がある[7].
  • これを利用した右方代入することもある[8][9][10].
  • これならばzsh以外のシェルでも比較的簡単に右方への代入ができる.
  • いわゆる"クリップボード"の容量がどれぐらいかはよくわからないので使いづらい[11].Copy/Paste "limits" - Apple Community
  • pbcopy内を空にする方法も知っておくと良い[9]
pbcopyを用いる
$ echo abc | pbcopy; x=$(pbpaste); echo $x
abc  # xに格納したabcを出力できた.

$ pbpaste
abc    #pbcopy内の確認.abcが格納されている.
pbcopyを用いる.複数行の場合.
$ echo "abc\nefg" | pbcopy; x=$(pbpaste); echo $x
abc
efg

$ pbpaste
abc
efg

bashでshoptコマンドを利用した方法

  • 当方の環境では動作を確認できなかったため紹介のみとする.
  • 参考[2]には,bashで右方代入する方法も紹介されている.
  • shoptコマンドを利用する.
  • shoptとは"bashの秘められた真のチカラを開放する[12]"感じのコマンドのようです.
  • -sは指定したオプションをONにできる.
  • lastpipeは"ジョブ制御が有効な場合,バックグラウンドでの実行ではないパイプラインの最後のコマンドを,現在のシェル環境で実行する[13]"というもので,zshのパイプと似た感じになるようです.
  • 併せて使うset -mは"monitorオプションを無効にする"ものだそうです[14].

追記2021/04/05
Bashに関しては以下
Bash: パイプからの入力を変数へ代入する(右方向への代入). - Qiita, https://qiita.com/BlackCat_617/items/2b3003c4bb79b5d89bc8

考察

  • zshでのみ有効であるので,汎用性は低い.
  • 個人で利用するのであれば問題ないと思われる.

結論

  • 右方代入の汎用性の高い方法はない.
  • zshならreadで簡単に実現できる.

参考

[1]まつもとゆきひろ,日経BP,まつもとゆきひろ言語のしくみ3-3 Streem文法再考,右方向代入の追加
[2]https://stackoverflow.com/questions/42963395/bash-assign-variable-from-pipe
bash: Assign variable from pipe? - Stack Overflow
[3]http://labs.timedia.co.jp/2011/09/shell-read-pipe-and-environment-variables.html
bash: readとパイプと環境変数 - TIM Labs
[4]https://sodocumentation.net/zsh/topic/5599/main-differences-from-bash
zsh - Main differences from bash | zsh Tutorial
[5]Bash Reference Manual - 3.2.2 Pipelines
https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Pipelines
[6]
https://www.atmarkit.co.jp/ait/articles/1811/28/news003.html
シェルスクリプトに挑戦しよう(10)「read」コマンドでキーボードからの入力を受け取る:“応用力”をつけるためのLinux再入門(30) - @IT
[7]https://macwiki.osdn.jp/wiki/index.php/OSXの固有コマンド#pbcopy.2C_pbpaste_.E2.80.A6_.E3.82.B3.E3.83.94.E3.83.BC.E3.81.A8.E3.83.9A.E3.83.BC.E3.82.B9.E3.83.88.E3.82.92.E3.82.B3.E3.83.9E.E3.83.B3.E3.83.89.E3.81.8B.E3.82.89
OSXの固有コマンド - MacWiki
[8]https://takuya-1st.hatenablog.jp/entry/2017/05/30/093000
pbcopy で標準出力の内容をecho表示を維持しつつコピーしたい - それマグで!
[9]https://blog.katsubemakito.net/macos/pasteboard-on-terminal
[macOS] Terminalからクリップボードを操作する - pbcopy, pbpaste
[10]https://apple.stackexchange.com/questions/43214/paste-text-stored-on-clipboard-to-a-variable-using-pbpaste
terminal - Paste text stored on Clipboard to a variable using pbpaste - Ask Different
[11]https://discussions.apple.com/thread/2396195
Copy/Paste "limits" - Apple Community
[12]https://geek-techiela.blogspot.com/2014/07/shoptbash.html
techiela: 超簡単!shoptでbashの”秘められた真のチカラ”を開放する 【サンプルあり】
[13]https://www.atmarkit.co.jp/ait/articles/1912/12/news034.html
【 shopt 】コマンド(応用編その1)――コマンドライン履歴の扱い方を変更する:Linux基本コマンドTips(362) - @IT
[14]https://www.atmarkit.co.jp/ait/articles/1805/17/news034.html
【 set 】コマンド(応用編1)――ファイルの上書きやシェルの終了、ジョブ終了後の通知動作を変更する:Linux基本コマンドTips(207) - @IT

8
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
6