web-dev-qa-db-ja.com

スクリプトで失われたLINESおよびCOLUMNS環境変数

以下を考慮してください。

me@mine:~$ cat a.sh 
#!/bin/bash
echo "Lines: " $LINES
echo "Columns: " $COLUMNS
me@mine:~$ ./a.sh 
Lines: 
Columns: 
me@mine:~$ echo "Lines: " $LINES
Lines:  52
me@mine:~$ echo "Columns: " $COLUMNS
Columns:  157
me@mine:~$ 

変数$LINESおよび$COLUMNSはシェル変数であり、not環境変数であるため、子プロセスにはエクスポートされません(ただし、xtermウィンドウのサイズを変更すると自動的に更新されます。リモートの場所からssh経由でログインした場合でも)。スクリプトに現在の端末サイズを知らせる方法はありますか?

編集:回避策としてこれが必要です この問題 :vi(vim、less、および同様のコマンドと同様)は、使用するたびに画面を台無しにします。端末を変更することはオプションではないため、回避策を探しています(スクロール$LINES linesは確かに完璧なソリューションではありませんが、少なくとも前の画面を失うよりはましです)

60
Davide

tputから行と列を取得できます。

#!/bin/bash

lines=$(tput lines)
columns=$(tput cols)

echo "Lines: " $lines
echo "Columns: " $columns
78
Puppe

この質問は人気があるため、少しの追加情報を含む新しい回答を追加します。

多くの場合、最新のシステムでは、$COLUMNSおよび$LINES変数はnot環境変数です。シェルは各コマンドの後にこれらの値を動的に設定し、通常、非対話型スクリプトからこれらの値にアクセスすることはできません。一部のプログラムは、exportでこれらの値を尊重しますが、この動作は標準化されておらず、普遍的にサポートされていません。

Bashは、以下を使用してcheckwinsizeオプションを有効にすると、(環境ではなく)processプロセスのスコープでこれらの変数を設定します。

shopt -s checkwinsize 

多くのシステムでは、デフォルトまたはシステム全体の起動ファイル(/ etc/bashrc または類似)、したがって、これらの変数が常に利用できるとは限らないことを覚えておく必要があります。 Cygwinなどの一部のシステムでは、このオプションはnot有効になっているため、上記の行を実行しない限り、Bashは$COLUMNSおよび$LINESを設定しませんそれを私たちに追加します 〜/ .bashrc


非対話型スクリプトを作成する場合、通常、デフォルトでは$LINESおよび$COLUMNSに依存することは望ましくありません(ただし、canをチェックして、ユーザーが必要に応じて、端末サイズを手動でオーバーライドします)。

代わりに、sttyおよびtputユーティリティは、スクリプトから端末サイズを決定するためのportable手段を提供します(説明されているコマンド以下は 現在POSIXの標準化が進行中 )です。

Puppe で受け入れられた回答に示されているように、tputを使用して、非常に簡単な方法で端末サイズを収集できます。

lines=$(tput lines)
columns=$(tput cols)

または、sizesttyクエリは、1行で端末の行と列の数を提供します(行数の後に2つのスペースとそれに続く列数として出力)。

size=$(stty size)  # "40  80" for example 

sttyプログラムには通常 GNU Coreutils が同梱されているため、tputのないシステムでもよく見られます。私は時々sttyアプローチを好むが、これはコマンドとサブシェルを1つ少なくするため(Cygwinでは高価)であるが、出力を行と列に解析する必要があるため、読みにくい場合がある:

lines=${size% *}
columns=${size#* }

上記の両方のアプローチは、POSIXシェルで機能します。特にBashの場合、 process substitution を使用して、前の例を単純化できます。

read lines columns < <(stty size) 

...これはtputの例よりも高速ですが、少なくとも私のマシンでは最初のsttyの実装よりも低速です。実際には、パフォーマンスへの影響はおそらく無視できます。プログラムに最適なアプローチを選択してください(またはターゲットシステムで使用可能なコマンドに基づいて)。


何らかの理由でスクリプトで$LINES$COLUMNSを使用したい場合は、これらの変数を環境にエクスポートするようにBashを構成できます。

trap 'export LINES COLUMNS' DEBUG

Bash DEBUGトラップは、プロンプトで各コマンドが入力される前に実行されるため、これを使用してこれらの変数をエクスポートできます。各コマンドでそれらを再エクスポートすることにより、端末サイズが変更された場合に環境変数が最新のままであることを保証します。この行を追加します .bashrc 上記のcheckwinsizeオプションとともに。個人用スクリプトでは問題なく動作しますが、共有されるスクリプトでこれらの変数を使用することはお勧めしません。

20
Cy Rossignol
eval $( resize )

その仕事をします...(xtermベースの端末上で)

6
Anthony
kill -s WINCH $$

変数を設定します。

5
elo

完了のために、「checkwinsize」オプションの設定はOPが探しているものとまったく同じですが、キャッチがあります。非対話型スクリプトではデフォルトでは設定されていませんが、スクリプトの先頭に次の行を追加して有効にすることができます。

shopt -s checkwinsize

残念ながら、LINESおよびCOLUMNS変数は、オプションを設定してもすぐには設定されません(少なくとも最後に試したとき)。代わりに、サブシェルが完了するまでBashを強制的に待機させる必要があり、その時点でこれらの変数が設定されます。したがって、この問題に対するBashのみの完全なソリューションは、次の行でスクリプトを開始することです。

shopt -s checkwinsize; (:;:)

その後、LINES変数とCOLUMNS変数を心ゆくまで使用できます。これらの変数は、外部ユーティリティを呼び出すことなく、端末のサイズが変更されるたびに正しい値にリセットされます。

4
Marc Coiffier

ランニング help export 役立つかもしれません?

me@mine:~$ cat a.sh 
#!/bin/bash
echo "Lines: " $LINES
echo "Columns: " $COLUMNS
me@mine:~$ ./a.sh 
Lines: 
Columns: 
me@mine:~$ echo "Lines: " $LINES
Lines:  52
me@mine:~$ echo "Columns: " $COLUMNS
Columns:  157
me@mine:~$ export LINES COLUMNS
me@mine:~$ ./a.sh 
Lines:  52
Columns:  157
me@mine:~$ 
2
SwordFish

あなたのシバンに言ってみましたか?

#!/bin/bash -i
2

bashの$LINESおよび$COLUMNSは、TTY ioctlの単なるシェルyラッパーであり、TTYのサイズと、サイズが変更されるたびに端末によって送信される信号を提供します。

これらのioctlを直接呼び出してTTYディメンションを取得する他の言語でプログラムを作成し、そのプログラムを使用できます。

編集:まあ、プログラムはすでに存在し、tputと呼ばれます。投票する Puppeのtputベースの回答

1
ndim
#!/bin/bash -i

-iは、現在、bash 4.2.10(1)-release on buntu 11.1で動作します。

$ cat show_dimensions.sh 
#!/bin/bash -i
printf "COLUMNS = %d\n" $COLUMNS
printf "LINES = %d\n" $LINES

$ ./show_dimensions.sh 
COLUMNS = 150
LINES = 101

$ bash --version
GNU bash, version 4.2.10(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

数値はウィンドウのサイズを変更すると変わります。トラップは、スクリプトがSIGWINCHを取得していることを示しています。

1
Seganku

次のようにexecコマンドで環境変数を使用しないのはなぜですか。

docker exec -ti -e LINES=$LINES -e COLUMNS=$COLUMNS  container /bin/bash
0
Classsic