2017-01-12 12 views
3

Как я могу выяснить, используется ли файловый дескриптор в Bash? Например, если у меня есть скрипт, который читает, записывает и закрывает fd 3, например.Как найти следующий доступный дескриптор файла в Bash?

exec 3< <(some command here) 
... 
cat <&3 
exec 3>&- 

, что это лучший способ гарантировать, что я не мешая какую-либо другой целью, для дескриптора, который может быть установлен перед запуском моего сценария? Должен ли я поставить весь мой скрипт в подоболочку?

+0

Я не вижу опции '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' дескриптор '' ''. Самый близкий подход - '-t number', который проверяет, открыт ли дескриптор файла _and_, подключенный к терминалу. Это ад, чтобы заставить скрипт интерпретировать цифры; вы не можете использовать '> & $ number', поэтому вам нужно будет возиться с суб-оболочками или чем-то еще. Нетрудно написать программу, которая проверяет данный дескриптор файла, но генерировать сценарий оболочки для использования произвольного числа может быть сложным. Поэтому большинство людей не беспокоится. –

ответ

6

В чистом bash, вы можете использовать следующий метод, чтобы увидеть, если данный дескриптор файла (3 в данном случае) имеется:

rco="$(true 2>/dev/null >&3; echo $?)" 
rci="$(true 2>/dev/null <&3; echo $?)" 
if [[ "${rco}${rci}" = "11" ]] ; then 
    echo "Cannot read or write fd 3, hence okay to use" 
fi 

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

С точки зрения находящих первый свободный дескриптор, вы можете использовать что-то вроде:

exec 3>/dev/null # Testing, comment out to make 
exec 4</dev/null # descriptor available. 

found=none 
for fd in {0..200}; do 
    rco="$(true 2>/dev/null >&${fd}; echo $?)" 
    rci="$(true 2>/dev/null <&${fd}; echo $?)" 
    [[ "${rco}${rci}" = "11" ]] && found=${fd} && break 
done 
echo "First free is ${found}" 

Запуск этого сценария дает 5 как первый свободный дескриптор, но вы можете играть вокруг с exec линий, чтобы увидеть, как делая ранее доступный, он позволит фрагменту кода найти его.


Как было отмечено в комментариях, системы, которые обеспечивают procfs/proc файловой системы) имеет другой способ, в котором они могут обнаружить свободные дескрипторы. Каталог /proc/PID/fd будет содержать запись для каждого дескриптора файла следующим образом:

pax> ls -1 /proc/$$/fd 
0 
1 
2 
255 

Таким образом, вы можете использовать сценарий, аналогичный приведенному выше, чтобы найти свободный вход в там:

exec 3>/dev/null # Testing, comment out to make 
exec 4</dev/null # descriptor available. 

found=none 
for fd in {0..200} ; do 
    [[ ! -e /proc/$$/fd/${fd} ]] && found=${fd} && break 
done 
echo "First free is ${found}" 

Просто продолжайте что не все системы, предоставляющие bash, обязательно будут иметь procfs (примеры BDS и CygWin являются примерами). Должно быть хорошо для Linux, если это таргетинг на ОС.


Конечно, вы все еще имеют вариант упаковки весь скрипт, как что-то вроде:

(
    # Your current script goes here 
) 

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

+1

Являются ли они одинаково результативными? Есть ли способ сделать это без каких-либо неуспехов? (примечание: мое знакомство с bash-производительностью ограничено, но я понимаю, что подголовки вообще лучше избегать, когда это возможно) – Kvass

+2

@ Kvass, если вы не делаете * обнаружение * в цикле с множеством итераций, это не имеет значения. Даже если * переадресации * находятся в цикле, скорее всего, вы обнаружите, какие бесплатные дескрипторы вам нужны перед * перед запуском цикла, и просто * используйте * эти дескрипторы в цикле. Не должно быть значительного штрафа за производительность. – paxdiablo

+0

Что не так с выбором номера, не входящего в список, предоставленный 'ls/proc/$$/fd'? – sorontar

3

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

Функция доступна с Баш 4.1+ (2009-12-31) {varname} style automatic file descriptor allocation

$ exec {var}>hellofile 
$ echo "$var" 
15 

$ echo "this is a test" >&${var} 
$ cat hellofile 
this is a test 

$ exec {var}>&-      # to close the fd. 

В самом деле, в Linux, вы можете увидеть открытые FDS с:

$ ls /proc/$$/fd 
0 1 2 255 
+0

Я получаю команду не найденной 'exec {my_var}', когда я пытаюсь это сделать – Kvass

+0

Вам понадобится bash 4.1 или более поздняя версия для этой функции. [{varname} присвоение дескриптора автоматического стиля стиля \t 4.1-alpha] (http://wiki.bash-hackers.org/scripting/bashchanges) – sorontar

+0

Я выполняю 4.4, хотя – Kvass

5

Другой ответ, что использует pre-bash-4.1 синтаксис делает много ненужных нерегулярных нерегулярных и избыточных проверок. Он также имеет произвольное отсечение для максимального числа FD.

Следующий код должен делать трюк без нереста некрополя (кроме вызова ulimit, если мы хотим получить приличную верхнюю границу номеров FD).

fd=2 max=$(ulimit -n) 

while ((++fd < max)); do 
    ! true <&$fd && break 
done 2>&- && echo $fd 
  • В основном мы просто перебирать возможные ФД, пока мы не достигнем одного мы не можем надуть.
  • Во избежание сообщения об ошибке Bad file descriptor, мы закрываем stderr для всей команды while.