В Bash, какой файл дескриптор 255, могу ли я его использовать?

pax -rwls'|.*/\(.*\)/audio\(\.mp3\)$|\1\2|p' \
    -s'|.*||' /path/to/Project .

Это будет использовать утилиту архиватора командной строки POSIX pax для создания жестких ссылок в текущем каталоге с именем parent_dirs_base.mp3 для каждого audio.mp3 , найденного с корнем в дереве по адресу / path / to / Project . При этом он будет печатать любые изменения имени файла, которые он вносит в stderr.

Используйте -k , чтобы предотвратить возможную перезапись существующих файлов с такими же именами, как у целей ссылки, или, что еще лучше, сначала перейдите в пустой каталог перед его запуском.

На мой взгляд, жесткое связывание в первую очередь дает существенное преимущество, чем прямое mv использование файлов, с которыми вы хотите работать: и это то, что вы получаете возможность убедиться, что ожидаемые результаты такие же, как у перед удалением оригиналов. После проверки вы можете:

find /path/to/Project -name audio.mp3 -exec rm {} +

... очистить и сократить ссылки на файлы по одной.

10
14.10.2018, 13:17
2 ответа

Этот файловый дескриптор 255является открытым дескриптором управляющего tty и используется только тогда, когда bashзапускается в интерактивном режиме.

Это позволяет вам перенаправить stderrв основной оболочке, сохраняя при этом возможность управления заданиями (, т.е. иметь возможность убивать процессы с помощью ^C, прерывать их с помощью ^Z и т. д. ).

Пример:

$ exec 2> >(tee /tmp/err); ls /nosuchfile; sleep 1000

Если вы попробуете это сделать в оболочке типа ksh93, которая просто использует файловый дескриптор 2 в качестве ссылки на управляющий терминал, процесс sleepстанет невосприимчивым к ^C и ^Z, и его нужно будет убит из другого окна/сеанса. Это связано с тем, что оболочка не сможет установить группу процессов sleepв качестве переднего плана в терминале с tcsetgrp(), поскольку файловый дескриптор 2 больше не указывает на терминал.

Это не специфично для bash, оно также используется в dashи zsh, только дескриптор не перемещается так высоко (, что обычно это 10 ).

zshтакже будет использовать этот fd для отображения подсказок и пользовательского ввода, поэтому будет работать следующее:

$ exec 2>/tmp/err
$ 

Это не имеет ничего общего с файловыми дескрипторами bash, используемыми при чтении скриптов и настройке каналов (, которые также дублируются той же функцией --move_to_high_fd()), как было предложено в другие ответы и комментарии.

bashиспользует такое большое число, чтобы разрешить использование fd, превышающего 9, в -перенаправлениях оболочки (, например.exec 87<filename); это не поддерживается в других оболочках.

Вы можете использовать этот дескриптор файла самостоятельно, но в этом мало смысла, потому что вы можете получить дескриптор того же самого того же управляющего терминала в любой команде с помощью ... < /dev/tty.

Анализ исходного кода bash:

В bashдескриптор файла управляющего терминала сохраняется в переменной shell_tty. Если оболочка является интерактивной, эта переменная инициализируется (при запуске или после неудачного выполнения )в jobs.c:initialize_job_control()путем дублирования ее из stderr(, если stderrподключен к терминалу )или напрямую открывается /dev/tty, а затем снова дублируется до более высокого fd с помощьюgeneral.c:move_to_high_fd():

int
initialize_job_control (force)
     int force;
{
 ...
  if (interactive == 0 && force == 0)
    {
     ...
    }
  else
    {
      shell_tty = -1;

      /* If forced_interactive is set, we skip the normal check that stderr
         is attached to a tty, so we need to check here.  If it's not, we
         need to see whether we have a controlling tty by opening /dev/tty,
         since trying to use job control tty pgrp manipulations on a non-tty
         is going to fail. */
      if (forced_interactive && isatty (fileno (stderr)) == 0)
        shell_tty = open ("/dev/tty", O_RDWR|O_NONBLOCK);

      /* Get our controlling terminal.  If job_control is set, or
         interactive is set, then this is an interactive shell no
         matter where fd 2 is directed. */
      if (shell_tty == -1)
        shell_tty = dup (fileno (stderr));        /* fd 2 */

      if (shell_tty != -1)
        shell_tty = move_to_high_fd (shell_tty, 1, -1);
     ...
    }

Если shell_ttyеще не является управляющим tty, то он делается так:

          /* If (and only if) we just set our process group to our pid,
             thereby becoming a process group leader, and the terminal
             is not in the same process group as our (new) process group,
             then set the terminal's process group to our (new) process
             group.  If that fails, set our process group back to what it
             was originally (so we can still read from the terminal) and
             turn off job control.  */
          if (shell_pgrp != original_pgrp && shell_pgrp != terminal_pgrp)
            {
              if (give_terminal_to (shell_pgrp, 0) < 0)
Затем

shell_ttyиспользуется для

  1. получить и установить группу процессов переднего плана с помощью tc[sg]etpgrpв jobs.c:maybe_give_terminal_to(), jobs.c:set_job_control()иjobs.c:give_terminal_to()

  2. получить и установить параметры termios(3)в jobs.c:get_tty_state()иjobs.c:set_tty_state()

  3. получить размер окна терминала с помощью ioctl(TIOCGWINSZ)в lib/sh/winsize.c:get_new_window_size().

move_to_high_fd()обычно используется со всеми дескрипторами временных файлов, используемымиbash(файлами скриптов, каналами и т. д. ), отсюда путаница в большинстве комментариев, которые заметно появляются в результатах поиска Google.

Файловые дескрипторы, используемые внутри bash, включая shell_tty, настроены на закрытие -при -exec, чтобы они не попадали в команды.

11
27.01.2020, 20:00

Последняя часть вашего вопроса:

Могу я им воспользоваться?

Изman bash:

Redirections using file descriptors greater than 9 should be used with care, as they may conflict with file descriptors the shell uses internally.

Итак, если вы имеете в виду использование как создание нового fd с этим номером, ответ будет отрицательным.

Если вы имеете в виду использовать как :«записать в этот fd»:

$ echo hello >/dev/fd/255"

Или читать оттуда:

$ read a </dev/fd/255
abc
$ echo "$a"
abc

Да.
Но, вероятно, лучше (независимо от оболочки )использовать /dev/ttyдля доступа к tty.

для чего нужен файловый дескриптор 255?

В качестве альтернативного подключения к tty в случае блокировки fd 1(/dev/stdout)и fd 0 (/dev/stdin).

Подробнее .

Другие оболочки могут использовать другое число (, например 10 в zsh)

$ zsh
mail% ls -l /proc/self/fd /proc/$$/fd/* &
[1] 3345
mail% lrwx------ 1 isaac isaac 64 Oct 14 09:46 /proc/3250/fd/0 -> /dev/pts/2
lrwx------ 1 isaac isaac 64 Oct 14 09:50 /proc/3250/fd/1 -> /dev/pts/2
lrwx------ 1 isaac isaac 64 Oct 14 09:50 /proc/3250/fd/10 -> /dev/pts/2
lrwx------ 1 isaac isaac 64 Oct 14 09:50 /proc/3250/fd/2 -> /dev/pts/2

/proc/self/fd:
total 0
lrwx------ 1 isaac isaac 64 Oct 14 09:50 0 -> /dev/pts/2
lrwx------ 1 isaac isaac 64 Oct 14 09:50 1 -> /dev/pts/2
lrwx------ 1 isaac isaac 64 Oct 14 09:50 2 -> /dev/pts/2
lr-x------ 1 isaac isaac 64 Oct 14 09:50 3 -> /proc/3345/fd

[1]  + done       ls -l /proc/self/fd /proc/$$/fd/*
mail% 

Из списка рассылки :

Fd 255 is used internally as a connection to the tty, so that it doesn't interfere with the use of exec to relocate fds. Bash also allocates high fds when handling a process substitution `<(foo)', for the same reason.
Andreas Schwab

17
27.01.2020, 20:00

Теги

Похожие вопросы