Jak działają deskryptory plików?
Czy ktoś może mi powiedzieć, dlaczego to nie działa? Bawię się z deskryptorami plików, ale czuję się trochę zagubiony.
#!/bin/bash
echo "This"
echo "is" >&2
echo "a" >&3
echo "test." >&4
Pierwsze trzy linie działają dobrze, ale ostatnie dwa błędy out. Dlaczego?
3 answers
Deskryptory plików 0, 1 i 2 są odpowiednio dla stdin, stdout i stderr.
Deskryptory plików 3, 4, .. 9 to dodatkowe pliki. Aby z nich korzystać, musisz je najpierw otworzyć. Na przykład:
exec 3<> /tmp/foo #open fd 3.
echo "test" >&3
exec 3>&- #close fd 3.
Aby uzyskać więcej informacji, zajrzyj do Advanced Bash-Scripting Guide: Rozdział 20. Przekierowanie We / Wy .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-16 17:13:54
To stare pytanie, ale jedno wymaga wyjaśnienia.
Podczas gdy odpowiedzi Carla Noruma i dogbane ' a są poprawne, założeniem jest zmienić skrypt, aby działał .
Chciałbym zwrócić uwagę na to, że nie musisz zmieniać skryptu :
#!/bin/bash
echo "This"
echo "is" >&2
echo "a" >&3
echo "test." >&4
To działa, jeśli wywołasz to inaczej:
./fdtest 3>&1 4>&1
Co oznacza przekierowanie deskryptorów plików 3 i 4 na 1 (co jest standardowym wyjściem).
Chodzi o to, że że skrypt jest idealny , jeśli chce pisać do deskryptorów innych niż 1 i 2 (stdout i stderr) , jeśli te deskryptory są dostarczane przez proces macierzysty .
Twój przykład jest całkiem interesujący, ponieważ ten skrypt może zapisywać do 4 różnych plików:
./fdtest >file1.txt 2>file2.txt 3>file3.txt 4>file4.txt
Teraz masz wyjście w 4 oddzielnych plikach:
$ for f in file*; do echo $f:; cat $f; done
file1.txt:
This
file2.txt:
is
file3.txt:
a
file4.txt:
test.
Co jest bardziej interesujące jest to, że twój program nie musi mieć uprawnień do zapisu te pliki, bo ich nie otwiera.
Na przykład, gdy uruchamiam sudo -s
, aby zmienić użytkownika na root, utwórz katalog jako root i spróbuj uruchomić następujące polecenie jako mój zwykły użytkownik (w moim przypadku rsp) w następujący sposób:
# su rsp -c '../fdtest >file1.txt 2>file2.txt 3>file3.txt 4>file4.txt'
Dostaję błąd:
bash: file1.txt: Permission denied
Ale jeśli zrobię przekierowanie poza su
:
# su rsp -c '../fdtest' >file1.txt 2>file2.txt 3>file3.txt 4>file4.txt
(zwróć uwagę na różnicę w pojedynczych cudzysłowach) to działa i dostaję:
# ls -alp
total 56
drwxr-xr-x 2 root root 4096 Jun 23 15:05 ./
drwxrwxr-x 3 rsp rsp 4096 Jun 23 15:01 ../
-rw-r--r-- 1 root root 5 Jun 23 15:05 file1.txt
-rw-r--r-- 1 root root 39 Jun 23 15:05 file2.txt
-rw-r--r-- 1 root root 2 Jun 23 15:05 file3.txt
-rw-r--r-- 1 root root 6 Jun 23 15:05 file4.txt
Które są 4 plikami należącymi do roota w katalog należący do roota - , mimo że skrypt nie miał uprawnień do tworzenia tych plików.
Innym przykładem może być użycie chroot jail lub kontenera i uruchomienie programu wewnątrz, w którym nie miałby on dostępu do tych plików, nawet jeśli byłby uruchomiony jako root i nadal przekierowywałby te deskryptory zewnętrznie tam, gdzie potrzebujesz, nie dając dostępu do całego systemu plików lub czegokolwiek innego temu skryptowi.
Chodzi o to, że odkryłeś bardzo ciekawy i przydatny mechanizm . Nie musisz otwierać wszystkich plików wewnątrz skryptu, jak sugerowano w innych odpowiedziach. Czasami przydatne jest przekierowanie ich podczas wywoływania skryptu.
Podsumowując to , to:
echo "This"
Jest właściwie równoważne:
echo "This" >&1
I uruchamianie programu jako:
./program >file.txt
Jest tym samym co:
./program 1>file.txt
Liczba 1 jest tylko liczbą domyślną i jest to stdout.
Ale nawet to program:
#!/bin/bash
echo "This"
Może spowodować błąd "złego deskryptora". Jak? Po uruchomieniu jako:
./fdtest2 >&-
Wyjście będzie:
./fdtest2: line 2: echo: write error: Bad file descriptor
Dodanie >&-
(co jest takie samo jak 1>&-
) oznacza zamknięcie standardowego wyjścia. Dodanie 2>&-
oznaczałoby zamknięcie stderr.
Możesz nawet zrobić bardziej skomplikowaną rzecz . Twój oryginalny scenariusz:
#!/bin/bash
echo "This"
echo "is" >&2
echo "a" >&3
echo "test." >&4
Po uruchomieniu Z just:
./fdtest
Druki:
This
is
./fdtest: line 4: 3: Bad file descriptor
./fdtest: line 5: 4: Bad file descriptor
Ale można zrobić deskryptory 3 i 4 działają, ale numer 1 fail by running:
./fdtest 3>&1 4>&1 1>&-
Wychodzi:
./fdtest: line 2: echo: write error: Bad file descriptor
is
a
test.
Jeśli chcesz, aby deskryptory 1 i 2 zawiedły, uruchom go w następujący sposób:
./fdtest 3>&1 4>&1 1>&- 2>&-
Otrzymujesz:
a
test.
Dlaczego? Nic nie zawiodło? udało się ale bez stderr (deskryptor pliku numer 2) nie widziałeś komunikatów o błędach!
Myślę, że bardzo przydatne jest eksperymentowanie w ten sposób, aby poczuć, jak deskryptory i ich przekierowania działają.
Twój scenariusz jest bardzo rzeczywiście ciekawy przykład - i twierdzę, że wcale nie jest zepsuty, po prostu źle go używałeś! :)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-15 09:55:35
To nie działa, ponieważ te deskryptory plików nie wskazują na nic! Standardowe domyślne deskryptory plików to standardowe wejście 0
, standardowe Wyjście 1
i standardowy strumień błędów 2
. Ponieważ skrypt nie otwiera żadnych innych plików, nie ma innych ważnych deskryptorów plików. Możesz otworzyć plik w bash używając exec
. Oto modyfikacja twojego przykładu:
#!/bin/bash
exec 3> out1 # open file 'out1' for writing, assign to fd 3
exec 4> out2 # open file 'out2' for writing, assign to fd 4
echo "This" # output to fd 1 (stdout)
echo "is" >&2 # output to fd 2 (stderr)
echo "a" >&3 # output to fd 3
echo "test." >&4 # output to fd 4
A teraz go uruchomimy:
$ ls
script
$ ./script
This
is
$ ls
out1 out2 script
$ cat out*
a
test.
$
Jak widać, dodatkowe wyjście zostało wysłane do żądanego pliki.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-16 17:16:56