Bagaimana cara menemukan lebar & tinggi jendela terminal?

295

Sebagai contoh sederhana, saya ingin menulis skrip CLI yang dapat mencetak =di seluruh lebar jendela terminal.

#!/usr/bin/env php
<?php
echo str_repeat('=', ???);

atau

#!/usr/bin/env python
print '=' * ???

atau

#!/usr/bin/env bash
x=0
while [ $x -lt ??? ]; do echo -n '='; let x=$x+1 done; echo
terlalu banyak php
sumber
Saya membuat lib node.js kecil ini untuk secara konsisten mendapatkan ukuran jendela yang benar npmjs.com/package/window-size
jonschlinkert

Jawaban:

562
  • tput cols memberi tahu Anda jumlah kolom.
  • tput lines memberi tahu Anda jumlah baris.
TonyUser
sumber
11
echo -e "lines\ncols"|tput -Suntuk mendapatkan garis dan cols lihat: linux.about.com/library/cmd/blcmdl1_tput.htm
nickl-
4
tputadalah perintah yang bagus dengan banyak perintah untuk membaca keadaan terminal, mengendalikan kursor dan properti teks, dan sebagainya.
Drew Noakes
2
Alias ​​praktis, misalnya alias dim="echo $(tput cols)x$(tput lines)":, yang mungkin menghasilkan 80x50.
Uskup
2
T&J ini mungkin dimiliki pada situs SE unix atau superuser.
mydoghasworms
2
@bishop perintah alias yang Anda berikan akan dievaluasi ketika shell bersumber. Anda perlu menggunakan tanda kutip tunggal untuk perintah alias. Seperti itu: alias dim='echo Terminal Dimensions: $(tput cols) columns x $(tput lines) rows'
brandonsimpkins
103

Dalam bash, variabel $LINESdan $COLUMNSlingkungan harus dapat melakukan trik. Ini akan diatur secara otomatis pada setiap perubahan ukuran terminal. (yaitu sinyal SIGWINCH )

David Dean
sumber
18
Namun, variabel lingkungan ini hanya tersedia untuk bash, dan tidak untuk semua program yang berjalan di dalam bash (seperti perl, python, ruby).
Br.Bill
9
Itu tidak berfungsi dalam apa pun kecuali sesi bash interaktif (jika Anda menjalankan skrip tidak interaktif lagi). Satu-satunya tempat Anda dapat menggunakannya dalam skrip adalah prompt_command di bash.
Doncho Gunchev
1
Sebenarnya, ini berfungsi dalam skrip non-interaktif, jika Anda mengatur checkwinsizeopsi. Misalnya, skrip non-interaktif ini akan mencetak dimensi terminal tempat terminal dijalankan: shopt -s checkwinsize; (:); echo $LINES $COLUMNS( checkwinsizeopsi hanya menginisialisasi variabel setelah menunggu subkulit selesai, itulah sebabnya kami memerlukan (:)pernyataan)
user3340662
$LINESdan $COLUMNSdiperbarui setelah SIGWINCHdikirim, sebenarnya setelah eksekusi perintah interaktif. Jika Anda mencoba memperbarui PS1dengan trap SIGWINCHAnda tidak dapat menggunakan $LINESdan $COLUMNS, mereka menyimpan nilai-nilai lama ((
gavenkoa
LINESdan COLUMNShanya ditetapkan sebagai variabel shell oleh bash. Bash tidak akan menetapkan mereka sebagai variabel lingkungan , kecuali jika Anda mengekspor variabel shell ini.
Markus Kuhn
67

Dan ada stty, dari coreutils

$ stty size
60 120 # <= sample output

Ini akan mencetak jumlah baris dan kolom, atau tinggi dan lebar, masing-masing.

Kemudian Anda dapat menggunakan salah satu cutatau awkuntuk mengekstrak bagian yang Anda inginkan.

Itu stty size | cut -d" " -f1untuk tinggi / garis dan stty size | cut -d" " -f2untuk lebar / kolom

Ryenus
sumber
Gaya ini tidak dapat bekerja dengan PIPE, disarankan menggunakan gaya tput.
liuyang1
6
masalah dengan tput adalah bahwa itu tidak selalu tersedia sementara stty tersedia di setiap tty. terima kasih untuk info itu!
iRaS
16
yes = | head -n$(($(tput lines) * $COLUMNS)) | tr -d '\n'
pixelbeat
sumber
3
Bukan jawaban langsung untuk pertanyaan, tetapi skrip demo yang bagus.
Chris Page
Teladan yang luar biasa!
Kurt Zhong
1
bagaimana sih aku melewatkan trperintah selama ini? (facepalm)
Marco Massenzio
Bahasa apa ini? Tampaknya samar-samar seperti skrip shell dengan kesalahan sintaksis. (Dalam shell Anda tidak dapat memiliki ruang di sekitar tugas sama dengan tanda, dan pipa pertama tampaknya tidak pada tempatnya.)
tripleee
2
yes '='akan menampilkan jumlah baris '=' yang tak terbatas dan perintah berikut cukup mengatur untuk mengisi terminal
pixelbeat
12

Untuk melakukan ini di lingkungan Windows CLI, cara terbaik yang bisa saya temukan adalah dengan menggunakan perintah mode dan parsing output.

function getTerminalSizeOnWindows() {
  $output = array();
  $size = array('width'=>0,'height'=>0);
  exec('mode',$output);
  foreach($output as $line) {
    $matches = array();
    $w = preg_match('/^\s*columns\:?\s*(\d+)\s*$/i',$line,$matches);
    if($w) {
      $size['width'] = intval($matches[1]);
    } else {
      $h = preg_match('/^\s*lines\:?\s*(\d+)\s*$/i',$line,$matches);
      if($h) {
        $size['height'] = intval($matches[1]);
      }
    }
    if($size['width'] AND $size['height']) {
      break;
    }
  }
  return $size;
}

Semoga bermanfaat!

CATATAN : Tinggi yang dikembalikan adalah jumlah garis dalam buffer, itu bukan jumlah garis yang terlihat di dalam jendela. Adakah opsi yang lebih baik di luar sana?

lyceus
sumber
3
Catat masalah dengan ini: output dari perintah ini khusus untuk lokal. Dengan kata lain, ini tidak akan berfungsi apa adanya di lokal Windows lainnya. Inilah yang saya dapatkan di Windows 7: i.imgur.com/Wrr7sWY.png
Camilo Martin
Menambahkan jawaban dengan solusi untuk itu. +1 meskipun!
Camilo Martin
10

Pada POSIX, pada akhirnya Anda ingin memohon panggilan TIOCGWINSZ(Get WINdow SiZe) ioctl(). Sebagian besar bahasa seharusnya memiliki semacam pembungkus untuk itu. Misalnya dalam Perl Anda dapat menggunakan Term :: Size :

use Term::Size qw( chars );

my ( $columns, $rows ) = chars \*STDOUT;
LeoNerd
sumber
1
Terima kasih untuk ini - menuntun saya ke arah yang benar. Elixir: :io.columnsErlang: io:columns(). erlang.org/doc/man/io.html#columns-0
Henrik N
2
Tidak ada TIOCGWINSZstandar POSIX dan ioctl()hanya ditentukan untuk fitur STREAMS usang.
osvein
4

Seperti yang saya sebutkan dalam jawaban lyceus, kodenya akan gagal pada Windows lokal non-Inggris karena output dari modemungkin tidak mengandung substring "kolom" atau "garis":

                                         output perintah mode

Anda dapat menemukan substring yang benar tanpa mencari teks:

 preg_match('/---+(\n[^|]+?){2}(?<cols>\d+)/', `mode`, $matches);
 $cols = $matches['cols'];

Perhatikan bahwa saya bahkan tidak peduli dengan garis karena tidak dapat diandalkan (dan saya sebenarnya tidak peduli dengan mereka).

Sunting: Menurut komentar tentang Windows 8 (oh Anda ...), saya pikir ini mungkin lebih dapat diandalkan:

 preg_match('/CON.*:(\n[^|]+?){3}(?<cols>\d+)/', `mode`, $matches);
 $cols = $matches['cols'];

Tapi cobalah mengujinya, karena saya tidak mengujinya.

Camilo Martin
sumber
Metode Anda tidak berfungsi di Win8. Saya mendapatkan lebih dari satu ---baris. i.imgur.com/4x02dqT.png
mpen
@ Mark Yah, bagus, itu CANTIK. Terima kasih Windows. <3 (pada catatan yang lebih relevan: Saya akan melihat cara memperbaikinya ... ketika Windows 9 keluar: P).
Camilo Martin
Ini adalah cara saya melakukannya: $mode = `mode`; list($rows, $cols) = array_slice(preg_split('/\n/', substr($mode, strpos($mode, 'CON:'))), 2, 2);. Dan kemudian saya mengganti semuanya kecuali angka.
Aleksandr Makov
@AleksandrMakov Saya ingin tahu apa yang terjadi jika ada bahasa dengan urutan seperti CON device status:? Mungkin mencocokkan sesuatu seperti CON.*:akan bekerja lebih baik.
Camilo Martin
1
@ Mark saya benar-benar mempertanyakan pada diri sendiri hal yang tepat. Kenapa sih aku melakukan itu? Dalam keraguan, saya hanya berasumsi ada beberapa alasan dan pergi bersamanya, lol.
Camilo Martin
1

Terinspirasi oleh jawaban @ pixelbeat, ini adalah bilah horizontal yang muncul tput, sedikit penyalahgunaan printfpadding / filling dantr

printf "%0$(tput cols)d" 0|tr '0' '='
huoneusto
sumber
0

Ada beberapa kasus di mana baris / kolom dan kolom Anda tidak cocok dengan ukuran sebenarnya dari "terminal" yang digunakan. Mungkin Anda mungkin tidak memiliki "tput" atau "stty".

Berikut adalah fungsi bash yang dapat Anda gunakan untuk memeriksa ukuran secara visual. Ini akan bekerja hingga 140 kolom x 80 baris. Anda dapat menyesuaikan maksimum sesuai kebutuhan.

function term_size
{
    local i=0 digits='' tens_fmt='' tens_args=()
    for i in {80..8}
    do
        echo $i $(( i - 2 ))
    done
    echo "If columns below wrap, LINES is first number in highest line above,"
    echo "If truncated, LINES is second number."
    for i in {1..14}
    do
        digits="${digits}1234567890"
        tens_fmt="${tens_fmt}%10d"
        tens_args=("${tens_args[@]}" $i)
    done
    printf "$tens_fmt\n" "${tens_args[@]}"
    echo "$digits"
}
pourhaus
sumber