Подтвердить что ты не робот

Почему символ перенаправления меняет поведение ls?

Итак, у меня всегда были сомнения относительно того, как перенаправление работает в следующих ситуациях:

  • Я набираю "ls", и все имена файлов разделяются пробелами:

    test$ touch a b c
    test$ ls
    a b c
    
  • Я использую " > " для перенаправления STDOUT в файл:

    test$ ls > ls.txt
    test$ cat ls.txt 
    a
    b
    c
    ls.txt
    

Интересно видеть, что формат изменяется, причем имена файлов разделяются символами новой строки. Кажется, что вывод генерируется ls -1.

Почему результат в последнем случае отличается от результата в первом случае? Может ли на самом деле увидеть символ " > ", чтобы он менял свое поведение?

4b9b3361

Ответ 1

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

Это документировано; страница man для ls документирует несколько вещей, которые зависят от того, является ли вывод терминалом:

  • Если вывод является терминалом, -C (для вывода с несколькими столбцами) является значением по умолчанию, в противном случае -1 (один столбец) является значением по умолчанию.
  • Если используется -l или -s, а вывод - терминал, сумма для всех размеров или блоков файлов, соответственно, печатается в строке перед листингом.
  • Если вывод является терминалом, по умолчанию используется -q. Это печатает неграфические символы как "?". В противном случае значения -v и -w являются значениями по умолчанию. Я немного неясен в отношении разницы между -v и -w. В документации, которую я упоминаю, -v заставляет "неотредактированную печать неграфических символов" и -w заставляет "грубую печать непечатаемых символов".

Ответ 2

Он не может видеть символ (который интерпретируется оболочкой), но он может узнать, идет ли вывод на терминал.

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

Другим приятным следствием этого поведения является то, что вы можете делать такие вещи, как ls | wc -l, не беспокоясь о нескольких файлах в одной строке. (Тем не менее, вам все равно придется беспокоиться о именах файлов, содержащих новые строки.)

Ответ 3

ls использует внутреннюю переменную с именем ls_mode, которая отличается для команд 3 типа "тип", которые реализует Gnu coreutils. Для ls, это LS_LS. Для dir, это LS_MULTI_COL и для vdir, it LS_LONG_FORMAT. Фактическая ls program указывает, что в зависимости от этой переменной формат вывода будет изменяться. Для ls это то, что он говорит

Если ls_mode является LS_LS, выходной формат зависит от того, выходное устройство является терминалом. Это для программы 'ls'.

Это соответствует вашему опыту изменения формата с расположением вывода. Если вы попробуете то же самое с dir, это будет не так.