Perintah ls beroperasi berbeda tergantung pada penerima

12

Bagaimana perintah seperti lstahu apa itu stdout?

Tampaknya lsberoperasi berbeda tergantung pada apa target stdout. Sebagai contoh jika saya lakukan:

ls /home/matt/tmp 

hasilnya adalah:

a.txt b.txt c.txt

Namun jika saya lakukan

ls /home/matt/tmp | cat

hasilnya adalah (yaitu baris baru per hasil):

a.txt
b.txt
c.txt

Proses ini melewati file deskriptor 1 untuk stdout kan? Bagaimana cara menentukan cara memformat hasil? Apakah deskriptor file mengungkapkan informasi?

Pak Freman
sumber
Terkait unix.stackexchange.com/q/157285/4671 , unix.stackexchange.com/q/63108/4671 dan mungkin lainnya. Tampaknya menjadi topik populer. Ini mungkin merupakan penipuan salah satunya.
Faheem Mitha

Jawaban:

22

Itu ls penggunaan Program isatty()untuk mengetahui apakah fd 1 adalah tty atau sesuatu yang lain (pipa, berkas, dll ...). Dari man 3 isatty:

int isatty(int fd);

DESKRIPSI
The isatty()tes fungsi apakah fdadalah file descriptor terbuka mengacu terminal


Pembaruan: Baris 1538 masuk ls.cdari coreutils (revisi git 43a987e1):

  if (isatty (STDOUT_FILENO))
    {
      format = many_per_line;
      /* See description of qmark_funny_chars, above.  */
      qmark_funny_chars = true;
    }

(many_per_line harus deskriptif diri.)

Stéphane Gimenez
sumber
8

Bukan jawaban yang pasti tetapi sebuah contoh. Dalam naskah Bash Anda dapat mencapai efek yang sama dengan test/ [['s -t:

-t FD True if FD is opened on a terminal.

Menggunakannya seperti ini:

bash-4.2$ where() { [[ -t 1 ]] && echo 'my output goes to TTY' || echo 'my output is redirected'; }

bash-4.2$ where
my output goes to TTY

bash-4.2$ where | cat
my output is redirected

bash-4.2$ where > test.file
bash-4.2$ cat test.file
my output is redirected
manatwork
sumber
6

Dari ls(1) manual OpenBSD :

Secara default, ls mencantumkan satu entri per baris ke output standar; pengecualian untuk terminal atau ketika opsi -C, -m, atau -x ditentukan.

Kemudian, nanti:

-1 (Angka numerik `` satu ''.) Memaksa output menjadi satu entri per baris. Ini adalah default ketika output tidak ke terminal.

[...]

-C Angkatan output multi-kolom; ini adalah default ketika output ke terminal.

Kusalananda
sumber
1

Anda dapat mengeksekusi lsdi pseudo-terminal menggunakan script perintah, menyalurkan output lske perintah lain dan mendapatkan format output yang sama seolah-olah tidak ada pipa seperti aliran stdout, yaitu seolah-olah stdout adalah terminal (tty).

Untuk mendasari isatty()mekanisme yang sudah ditunjukkan oleh Stéphane Gimenez melihat ls.c .

ls -G /
ls -G / | cat
script -q /dev/null ls -G / | sed $'s/\r$//g' | cat

# tty | cat
# script -q /dev/null tty | cat
ron
sumber