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 {} +
... очистить и сократить ссылки на файлы по одной.
Этот файловый дескриптор 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
используется для
получить и установить группу процессов переднего плана с помощью tc[sg]etpgrp
в jobs.c:maybe_give_terminal_to()
, jobs.c:set_job_control()
иjobs.c:give_terminal_to()
получить и установить параметры termios(3)
в jobs.c:get_tty_state()
иjobs.c:set_tty_state()
получить размер окна терминала с помощью ioctl(TIOCGWINSZ)
в lib/sh/winsize.c:get_new_window_size()
.
move_to_high_fd()
обычно используется со всеми дескрипторами временных файлов, используемымиbash
(файлами скриптов, каналами и т. д. ), отсюда путаница в большинстве комментариев, которые заметно появляются в результатах поиска Google.
Файловые дескрипторы, используемые внутри bash
, включая shell_tty
, настроены на закрытие -при -exec, чтобы они не попадали в команды.
Последняя часть вашего вопроса:
Из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
.
В качестве альтернативного подключения к 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