Przekierowania i potoki, standardowe wejście i wyjście procesu

Wejście i wyjście standardowe oraz wyjście standardowe błędów


Procesy (uruchomione programy) w trybie tekstowym mają od początku działania przyporządkowane trzy otwarte deskryptory: Przez domniemanie wejście standardowe skojarzone jest z klawiaturą terminala, zaś wyjście standardowe i standardowe wyjście błędów z oknem tekstowym terminala. Dlatego też pojawiają się w nim zarówno użyteczne wyniki działania programów, jak i komunikaty o błędach.

Przekierowania


Domniemane przyporządkowanie deskryptorów można zmienić (na przykład chcąc wprowadzić z pliku dużą ilość danych lub zapisać w pliku dużą ilość wyników) przy użyciu operatorów przekierowania:

program < plik -wejście standardowe procesu zostanie skojarzone z danym plikiem (uwaga: plik musi istnieć)
program > plik -wyjście standardowe procesu zostanie skojarzone z danym plikiem. Jeżeli plik nie istniał, będzie utworzony (jako pusty plik). Jeżli plik już istniał, jego dotychczasowa zawartość zostanie usunięta (nadpisana)
program >> plik -wyjście standardowe procesu zostanie skojarzone z danym plikiem. Jeśli plik nie istniał, będzie utworzony (jako pusty plik). Jeśli plik już istniał, jego dotychczasowa zawartość nie zostanie usunięta (proces będzie dopisywał do niej swoje wyniki)
program 2> plik -standardowe wyjście błędów procesu zostanie skojarzone z danym plikiem. Jeśli plik nie istniał, będzie utworzony (jako pusty plik). Jeśli plik już istniał, jego dotychczasowa zawartość zostanie usunięta (nadpisana)

ZADANIA:


1. Przy użyciu polecenia ls -l > plik zapisać w pliku zawartość bieżącego katalogu (przekierować wyjście polecenia do pliku).

2. Napisać nieduży program w języku C zawierający kilka błędów składniowych, skompilować go przy użyciu polecenia gcc program.c i obejrzeć wyświetlony wykaz błędów. Użyć przekierowania standardowego wyjścia błędów: gcc program.c 2> plik, obejrzeć zawartość utworzonego pliku.

3. Utworzyć program w języku C:
#include <stdio.h>
int main(){
	int n;
	scanf("%d",&n);
	printf("%d", n);
	return 0;
}
Następnie uruchomić go i sprawdzić działanie.

3. Utworzyć kolejny program w języku C:
#include <stdio.h>
int main(int argc, char **argv){
	printf("%s", argv[1]);
	return 0;
}
Skompilować, a następnie uruchomić go poleceniem ./a.out 5. Czym różnią się oba programy?
Język poleceń bash'a może być uważany za skryptowy język programowania. Oznacza to, że polecenia mogą nie tylko być używane w linii poleceń, ale również mogą być umieszczane (w większej liczbie) w plikach (nazywanych skryptami), które następnie są uruchamiane jako całość. W związku z tym skrypty muszą mieć nadane zarówno prawo do odczytu (r), jak i do wykonywania (x) dla tego, kto je będzie uruchamiał.

Języki skryptowe (interpretowane) różnią się od języków kompilowanych tym, że programy w nich napisane nie podlegają kompilacji (tłumaczeniu w całości i dołączaniu podprogramów bibliotecznych) na język wewnętrzny komputera, tylko pojedyncze instrukcje podlegają tłumaczeniu "na bieżąco" (są interpretowane przez program interpretera poleceń - w tym przypadku przez bash'a). Niektóre języki programowania (na przykład Basic) mogą być używane zarówno jako języki interpretowane, jak i kompilowane. Programy skompilowane są wykonywane dużo szybciej, niż programy interpretowane, ale wprowadzanie w nich zmian wymaga później ponownej kompilacji całości.

W systemach uniksowych zazwyczaj jest dostępnych co najmniej kilka różnych interpreterów, z których jeden (zwykle bash) uważany jest za interpreter domyślny. W przypadku, gdy skrypt przeznaczony jest do wykonywania pod bieżącym interpreterem (tym, z którym aktualnie współpracujemy w oknie tekstowym), nie ma potrzeby umieszczania na jego początku żadnej dodatkowej informacji, natomiast jeśli chcemy wymusić interpretację skryptu przez pewien wybrany interpreter, umieszczamy na jego początku linię sterującą o postaci:

 #!........ (bezwzględna ścieżka dostępu do programu interpretera)

Przykłady:

	#!/bin/bash
	#!/bin/csh
Innym sposobem jest podanie polecenia o postaci:
nazwa_interpretera nazwa_skryptu

Przykład:
	
	sh moj_skrypt


Zad. 1
Utworzyć plik o dowolnej nazwie i następującej zawartości:
 clear
 echo "To jest pierwszy napis"
 echo "A to jest drugi napis"
 exit 0
Zad. 2
Napisać i uruchomić skrypt wczytujący i wyświetlający łańcuch (napis):
 clear
 echo -n "Napisz cos: "
 read x
 echo "Otrzymalem napis: $x"
 exit 0
Zad. 3
Utworzyć skrypt, który w bieżącym katalogu tworzy podkatalog Teksty, nastepnie towrzy pusty plik wiersz.txt i ustanawia prawa dostępu 755 do tego pliku. Na końcu wyświetla napis o zakończeniu działania.



Skrypty (podobnie, jak inne programy uruchamiane w trybie tekstowym) mogą w chwili swojego uruchomienia otrzymać pewną liczbę argumentów wywołania podanych w linii poleceń:
 nazwa_programu argument_1 argument_2 ... argument_n
Podawanie argumentów jest najbardziej podstawowym sposobem podawania danych dla programu (zwykle są to dane o charakterze "sterującym", a właściwy strumień danych jest podawany przez wejście standardowe). Programy mogą mieć stałą lub zmienną liczbę argumentów. UWAGA: sama nazwa programu też jest uważana za argument (o numerze 0).

Zad. 4
Napisać i uruchomić skrypt, który: a) otrzymuje trzy argumenty wywołania i kolejno je wyświetla:
 echo $1 $2 $3
b) otrzymuje dowolną liczbę argumentów wywołania i wyświetla je wszystkie:
 echo $*
c) otrzymuje dowolną liczbę argumentów wywołania i wyświetla, ile ich otrzymał:
 echo $#

Zad. 5
Utworzyć dwa proste skrypty o nazwach odpowiednio Pierwszy i Drugi, które robią cokolwiek (np. wyświetlają coś), a następnie skrypt, który po kolei wywołuje je w swojej treści (jako podprogramy):
 ...
 echo Uruchamiam pierwszy skrypt
 ./Pierwszy
 sleep 3
 echo Uruchamiam drugi skrypt
 ./Drugi
 sleep 3
 echo Koncze dzialanie
 exit 0