it-swarm-tr.com

Ne zaman ek bir dosya tanımlayıcı kullanırsınız?

Dosya tanımlayıcı oluşturabileceğinizi ve çıktıyı ona yönlendirebileceğinizi biliyorum. Örneğin.

exec 3<> /tmp/foo # open fd 3.
echo a >&3 # write to it
exec 3>&- # close fd 3.

Ancak aynı şeyi dosya tanıtıcısı olmadan da yapabilirsiniz:

FILE=/tmp/foo
echo a > "$FILE"

Ne zaman ek bir dosya tanımlayıcı kullanmak gerekir iyi bir örnek arıyorum.

80
dogbane

Çoğu komut tek bir giriş kanalına (standart giriş, dosya tanımlayıcı 0) ve tek bir çıkış kanalına (standart çıkış, dosya tanımlayıcı 1) sahiptir veya kendi başlarına açtıkları birkaç dosyada çalışır (böylece onlara bir dosya adı iletirsiniz). (Bu, genellikle kullanıcıya sonuna kadar filtre uygulayan standart hatadan (fd 2) ek olarak bulunur.) Bununla birlikte, bazen birkaç kaynaktan veya birkaç hedefe filtre görevi gören bir komutun olması uygundur. Örneğin, bir dosyadaki tek sayılı satırları çift sayılı olanlardan ayıran basit bir komut dosyası

while IFS= read -r line; do
  printf '%s\n' "$line"
  if IFS= read -r line; then printf '%s\n' "$line" >&3; fi
done >odd.txt 3>even.txt

Şimdi tek sayı satırlarına ve çift numaralı satırlara farklı bir filtre uygulamak istediğinizi varsayalım (ancak bunları tekrar bir araya getirmezseniz, bu genel olarak Kabuktan mümkün olmayan farklı bir sorun olacaktır). Kabukta, bir komutun standart çıktısını yalnızca başka bir komuta bağlayabilirsiniz; başka bir dosya tanımlayıcısını yönlendirmek için önce fd 1'e yönlendirmeniz gerekir.

{ while … done | odd-filter >filtered-odd.txt; } 3>&1 | even-filter >filtered-even.txt

Bir başka, daha basit kullanım durumu bir komutun hata çıktısını filtrelemek .

exec M>&N, Komut dosyasının geri kalanı için bir dosya tanımlayıcısını başka bir dosyaya yeniden yönlendirir (veya başka bir komut dosya tanımlayıcılarını tekrar değiştirene kadar). exec M>&N Ve somecommand M>&N Arasında bazı çakışmalar var. exec formu, iç içe yerleştirilmesi gerekmediği için daha güçlüdür:

exec 8<&0 9>&1
exec >output12
command1
exec <input23
command2
exec >&9
command3
exec <&8

İlginizi çekebilecek diğer örnekler:

Ve daha da fazla örnek için:

Not; Bu şaşırtıcı bir soru fd 3 üzerinden yeniden yönlendirme kullanan sitede en çok oylanan yazı) yazarından geliyor !

İşte bash script chattiness control olarak ekstra FD'lerin kullanımına bir örnek:

#!/bin/bash

log() {
    echo $* >&3
}
info() {
    echo $* >&4
}
err() {
    echo $* >&2
}
debug() {
    echo $* >&5
}

VERBOSE=1

while [[ $# -gt 0 ]]; do
    ARG=$1
    shift
    case $ARG in
        "-vv")
            VERBOSE=3
        ;;
        "-v")
            VERBOSE=2
        ;;
        "-q")
            VERBOSE=0
        ;;
        # More flags
        *)
        echo -n
        # Linear args
        ;;
    esac
done

for i in 1 2 3; do
    fd=$(expr 2 + $i)
    if [[ $VERBOSE -ge $i ]]; then
        eval "exec $fd>&1"
    else
        eval "exec $fd> /dev/null"
    fi
done

err "This will _always_ show up."
log "This is normally displayed, but can be prevented with -q"
info "This will only show up if -v is passed"
debug "This will show up for -vv"
14
Fordi

Adlandırılmış kanallar (fifos) bağlamında, ek bir dosya tanıtıcısının kullanılması, engellemeyen borulama davranışını etkinleştirebilir.

(
rm -f fifo
mkfifo fifo
exec 3<fifo   # open fifo for reading
trap "exit" 1 2 3 15
exec cat fifo | nl
) &
bpid=$!

(
exec 3>fifo  # open fifo for writing
trap "exit" 1 2 3 15
while true;
do
    echo "blah" > fifo
done
)
#kill -TERM $bpid

Bakınız: Adlandırılmış Boru komut dosyasında erken kapanıyor mu?

8
chad

Ekstra dosya tanımlayıcı, stdout'u bir değişkende yakalamak istediğinizde, ancak yine de ekrana yazmak istediğinizde, örneğin bir bash script kullanıcı arayüzünde iyi bir dosya tanımlayıcısıdır.

arg1 string to echo 
arg2 flag 0,1 print or not print to 3rd fd stdout descriptor   
function ecko3 {  
if [ "$2" -eq 1 ]; then 
    exec 3>$(tty) 
    echo -en "$1" | tee >(cat - >&3)
    exec 3>&- 
else 
    echo -en "$1"  
fi 
}

Ek bir dosya tanımlayıcı kullanırken (Bash'te) uygun göründüğü başka bir senaryo:

Komut satırı parametrelerinin Shell script şifre güvenliği

env -i bash --norc   # clean up environment
set +o history
read -s -p "Enter your password: " passwd
exec 3<<<"$passwd"
mycommand <&3  # cat /dev/stdin in mycommand
3
bernard

Örnek: komut dosyalarını dosya kilitleriyle seri olarak çalışmaya zorlamak için flock kullanma

Bir örnek, komut dosyalarını seri olarak sistem çapında çalışmaya zorlamak için dosya kilitleme özelliğini kullanmaktır. Aynı dosyada aynı türden iki komut dosyasının çalışmasını istemiyorsanız bu yararlıdır. Aksi takdirde, iki komut dosyası birbirine müdahale eder ve muhtemelen bozuk verilerdir.

#exit if any command returns a non-zero exit code (like flock when it fails to lock)
set -e

#open file descriptor 3 for writing
exec 3> /tmp/file.lock

#create an exclusive lock on the file using file descriptor 3
#exit if lock could not be obtained
flock -n 3

#execute serial code

#remove the file while the lock is still obtained
rm -f /tmp/file.lock

#close the open file handle which releases the file lock and disk space
exec 3>&-

Kilitleme ve kilit açma işlevini tanımlayarak sürüyü işlevsel olarak kullanma

Bu kilitleme/kilit açma mantığını yeniden kullanılabilir işlevlere de sarabilirsiniz. Aşağıdaki trap Shell builtin komut dosyası çıktığında dosya kilidini otomatik olarak serbest bırakır (hata veya başarı). trap dosya kilitlerinizi temizlemeye yardımcı olur. Yol /tmp/file.lock sabit kodlanmış bir yol olmalıdır, böylece birden fazla komut dosyası kilitlenmeye çalışabilir.

# obtain a file lock and automatically unlock it when the script exits
function lock() {
  exec 3> /tmp/file.lock
  flock -n 3 && trap unlock EXIT
}

# release the file lock so another program can obtain the lock
function unlock() {
  # only delete if the file descriptor 3 is open
  if { >&3 ; } &> /dev/null; then
    rm -f /tmp/file.lock
  fi
  #close the file handle which releases the file lock
  exec 3>&-
}

Yukarıdaki unlock mantığı, kilit serbest bırakılmadan önce dosyayı silmektir. Bu şekilde kilit dosyasını temizler. Dosya silindiğinden, bu programın başka bir örneği dosya kilidini alabilir.

Kodlarda kilitleme ve kilit açma işlevlerinin kullanımı

Aşağıdaki örneklerde olduğu gibi komut dosyalarınızda kullanabilirsiniz.

#exit if any command returns a non-zero exit code (like flock when it fails to lock)
set -e

#try to lock (else exit because of non-zero exit code)
lock

#system-wide serial locked code

unlock

#non-serial code

Kodunuzun kilitlenene kadar beklemesini istiyorsanız komut dosyasını aşağıdaki gibi ayarlayabilirsiniz:

set -e

#wait for lock to be successfully obtained
while ! lock 2> /dev/null; do
  sleep .1
done

#system-wide serial locked code

unlock

#non-serial code
1
Sam Gleske

Somut bir örnek olarak, sadece bir alt komuttan zamanlama bilgisine ihtiyaç duyan bir senaryo yazdım. Fazladan bir dosya tanımlayıcı kullanmak, alt komutun stdout'unu veya stderr'ini kesmeden time komutunun stderr'ini yakalamama izin verdi.

(time ls -9 2>&3) 3>&2 2> time.txt

Bunun yaptığı şey, ls 'nin stderr - fd 3, fd 3' ü betiğin stderr 'a ve time' stderr 'in bir dosyaya işaretidir. Komut dosyası çalıştırıldığında, stdout ve stderr, her zamanki gibi yeniden yönlendirilebilen alt komutlarla aynıdır. Dosyaya yalnızca time çıktısı yönlendirilir.

$ echo '(time ls my-example-script.sh missing-file 2>&3) 3>&2 2> time.txt' > my-example-script.sh
$ chmod +x my-example-script.sh 
$ ./my-example-script.sh 
ls: missing-file: No such file or directory
my-example-script.sh
$ ./my-example-script.sh > /dev/null
ls: missing-file: No such file or directory
$ ./my-example-script.sh 2> /dev/null
my-example-script.sh
$ cat time.txt

real    0m0.002s
user    0m0.001s
sys 0m0.001s
1
Ben Blank