Mostrando entradas con la etiqueta español. Mostrar todas las entradas
Mostrando entradas con la etiqueta español. Mostrar todas las entradas

viernes, 2 de agosto de 2013

Muy rápido, muy fácil, reproductor de audio con Python (Ahora con video)

En el articulo pasado hicimos un reproductor de audio, este únicamente reproducía pistas de audio, en esta entrega vamos a hacer que mediante un modulo nuevo y unas cuantas lineas extra sea posible reproducir vídeo.

Qt es un framework que ofrece herramientas muy poderosas, una de estas es el modulo Phonon, el cual nos da la posibilidad de reproducir audio y vídeo, para este fin usaremos el widget VideoWidget, el cual viene incluido dentro del grupo de widgets de la librería Phonon. el VideoWidget será enlazado a un AudioObject  y a un MediaObject, este ultimo sera el encargado de cambiar el archivo fuente e iniciar la reproducción.
Todo lo anterior sera agrupado en una clase para intentar hacer esto un poco más modular y poder reusarlo de ser necesario.
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
from PySide.QtGui import QApplication
from PySide.phonon import Phonon
from PySide import QtCore, QtGui


class player(Phonon.VideoWidget):

    def __init__(self, file_path):
        super(player, self).__init__(parent=None)
        self.setWindowTitle("Video")
        QtGui.QApplication.addLibraryPath(
            os.path.join(os.path.dirname(__file__), 'plugins'))
        media_src = Phonon.MediaSource(file_path)
        self.file_path = file_path
        media_obj = Phonon.MediaObject()
        media_obj.setCurrentSource(media_src)
        Phonon.createPath(media_obj, self)
        self.media_obj = media_obj
        audio_out = Phonon.AudioOutput(Phonon.VideoCategory)
        Phonon.createPath(media_obj, audio_out)
        self.audio_out = audio_out
        self.media_obj.setTickInterval(1000)
        self.media_obj.tick.connect(self.alAvanzar)
        self.media_obj.stateChanged.connect(self.alCambiarEstado)

    def alAvanzar(self, tiempo):
        pass

    def alCambiarEstado(self, new, old):
        pass

    def play(self):
        self.media_obj.play()

    def pause(self):
        self.media_obj.pause()

    def stop(self):
        self.media_obj.stop()

    def state(self):
        return self.media_obj.state()

En el código anterior vemos como una la clase player hereda de la clase Phonon.VideoWidget y tiene como atributos un MediaObject y un AudioOutput, los cuales sirven como control de reproducción y salida de audio respectivamente, y los tres son enlazados en el constructor de la clase en la linea 21 y 24.

Ahora veremos la nueva versión del reproductor, con las mejoras respectivas para implementar nuestro player de vídeo:
from PySide import QtCore, QtGui, phonon, QtUiTools
from PySide.phonon import Phonon

from videopanel import player


class Reproductor(QtGui.QWidget):

    def __init__(self):
        super(Reproductor, self).__init__(parent=None)
        self.setWindowTitle("Python Simple Player")
        self.gridLayout = QtGui.QGridLayout(self)
        loader = QtUiTools.QUiLoader()
        file = QtCore.QFile("repro.ui")
        file.open(QtCore.QFile.ReadOnly)
        self.ui = loader.load(file, self)
        file.close()
        self.gridLayout.addWidget(self.ui, 0, 0, 1, 1)
        # seccion multimedia
        self.audioOutput = Phonon.AudioOutput(Phonon.MusicCategory, self)
        self.mediaObject = Phonon.MediaObject(self)
        Phonon.createPath(self.mediaObject, self.audioOutput)
        self.mediaObject.setTickInterval(1000)
        #
        self.ui.lcdAvance.display("00:00")
        QtCore.QObject.connect(
            self.ui.btnArchivo,
            QtCore.SIGNAL("clicked()"),
            self.openFile)
        QtCore.QObject.connect(
            self.ui.btnPlay,
            QtCore.SIGNAL("clicked()"),
            self.play)
        self.mediaObject.tick.connect(self.alAvanzar)
        self.mediaObject.stateChanged.connect(self.alCambiarEstado)
        #----------------------
        self.player = None

    def alAvanzar(self, tiempo):
        displayTime = QtCore.QTime(
            0, (tiempo / 60000) %
            60, (tiempo / 1000) %
            60)
        self.ui.lcdAvance.display(displayTime.toString('mm:ss'))

    def alCambiarEstado(self, new, old):
        if self.mediaObject.state() == Phonon.State.StoppedState:
            self.ui.btnPlay.setEnabled(True)
        elif self.mediaObject.state() == Phonon.State.PlayingState:
            self.ui.btnPlay.setText("||")  # .setEnabled(False)

    def play(self):
        if self.player:
            if self.player.state() == Phonon.State.PlayingState:
                self.player.pause()
                self.player.show()
                self.ui.btnPlay.setText(">")
            else:
                self.player.show()
                self.player.play()
                self.ui.lblNombre.setText(self.player.file_path)
                self.ui.btnPlay.setText("||")
        else:
            if self.mediaObject.state() == Phonon.State.PlayingState:
                self.mediaObject.pause()
                self.ui.btnPlay.setText(">")
            else:
                self.mediaObject.play()
                #///////////////////////////////////
                meta = self.mediaObject.metaData()
                print(meta)
                meta["TITLE"] = meta[
                    "TITLE"] if "TITLE" in meta else "Indefinido"
                meta["ARTIST"] = meta[
                    "ARTIST"] if "ARTIST" in meta else "SinNombre"
                label = "{TITLE} by {ARTIST}".format(**meta)
                self.ui.lblNombre.setText(label)
                #///////////////////////////////////
                self.ui.btnPlay.setText("||")

    def openFile(self):
        fileName = QtGui.QFileDialog.getOpenFileName(
            self,
            u"Abrir Archivo",
            u".",
            u"Archivos de Audio (*.mp3 *.wav *.ogg);;Archivos de Video (*.mp4 *.mpg *.avi)")
        if fileName[1]:
            self.path = fileName[0]
            self.mediaObject.setCurrentSource(
                Phonon.MediaSource(self.path))
            self.ui.btnPlay.setText(">")
            self.ui.lblNombre.setText("...")
            self.ui.lcdAvance.display("00:00")
            if fileName[0][-3:] in "mp4 mpg avi".split():
                self.player = player(fileName[0])
                self.player.alAvanzar = self.alAvanzar
                self.player.alCambiarEstado = self.alCambiarEstado
            else:
                self.player = None

if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    rep = Reproductor()
    rep.show()
    sys.exit(app.exec_())

Ahora lo primero que vemos es una modificación en el constructor, en el cual creamos una variable de clase llamada player que es nula (linea 38). Luego vemos en el método play una condición en la cual si el player es diferente de nulo llama al objeto player para que este inicie la reproducción o la detenga. Finalmente en el método openFile vemos que se verifica la extensión del archivo a reproducir, si es un archivo de vídeo la variable de clase player deja de ser nula y se convierte en una instancia de la clase player que ya habíamos hecho antes, de lo contrario sigue siendo nula.

Espero que les guste y que les sirva, dejo el código en GitHub, si tienen sugerencias o demás comenten.

jueves, 1 de agosto de 2013

Entendiendo Javascript (VI)


Hasta el momento todo lo abarcado en los artículos ha permitido entender un poco mejor muchos de los pormenores de este interesante pero complejo lenguaje, pero muy poco se ha hecho por entender cómo modificar lo que el usuario utiliza, qué es en esencia lo que más necesita un usuario JavaScript, por esto en esta entrega vamos a empezar con la exploración de el objeto donde se almacena el contenido de la página, el objeto document.

Peleando con el documento
Ya habíamos hablado acerca de que en el momento en el que el navegador carga una página web toma todo el contenido HTML y lo convierte en objetos, estos objetos en realidad son nodos "manipulables", que a su vez contienen otros nodos. A esto se le llama document. Es muy importante resaltar que todo lo que hay en el document es un nodo, a continuación vamos a ver un ejemplo de esto.
<html>
    <head>
        <title>El Documento...</title>
    </head>
    <body>
        <h1>El Documento</h1>
        <div>Este es un ejemplo...</div>
    </body>
</html>

Si hiciéramos un esquema a manera de árbol de cómo se ve este HTML tendríamos:
De esta manera vemos como el nodo html es el padre inmediato de head y body, head es el padre de title y title tiene una propiedad llamada text, cuyo valor es "El documento...". body es el padre de h1 y div, los cuales a su vez tienen cada uno como propiedad text "El Documento" y "Ejemplo de documento..." respectivamente.

Muy bonito pero...
¿Para qué nos sirve entender esto?, la idea de entender esto es poder desplazarnos por el árbol sin depender únicamente de los identificadores, las etiquetas o los nombres.

Esta bien, y ¿Cómo me desplazo?
Esa es la parte divertida, porque para desplazarnos el objeto document nos ofrece unas herramientas, a continuación vamos a ver algunas de estas:
Orden Descripción
document.getElementById(valor) Retorna el elemento que en el atributo id tenga el valor especificado.
document.getElementsByName(nombre) Retorna una lista de todos los elementos que tengan el nombre especificado.
document.getElementsByTagName(tag) Retorna una lista de todos los elementos hechos con con el tag especificado

Y Para Terminar...
Vamos a hacer un ejemplo de una función que busca el título de nuestra página y lo cambia, otra que cambia el contenido de un div y su color de fondo y cada una va a ser asociada a un botón. Después del código esta el ejemplo.

<html>
    <head>
        <title>El Documento...</title>
        <script>
             function cambiarTituloPor(nuevoTitulo){
                document.getElementsByTagName("title")[0].innerHTML=nuevoTitulo;
             }
             function cambiarContenidoPor(nuevoContenido){
                var elemento = document.getElementById("modificable");
                elemento.innerHTML=nuevoContenido;
                var estilo = document.createAttribute("style");
                estilo.value = "background-color:#1662A8;";
                elemento.setAttributeNode(estilo);
             }
        </script>
    </head>
    <body>
        <h1>El Documento</h1>
        <div id="modificable">Este es un ejemplo...</div>
        <button onclick="cambiarTituloPor(prompt('Nuevo Título','Hola Mundo!!!'))">Cambiar Título</button>
        <button onclick="cambiarContenidoPor(prompt('Nuevo Contenido','Estoy aprendiendo JavaScript...'))">Cambiar Div</button>
    </body>
</html>

Este es un ejemplo...

martes, 30 de julio de 2013

Muy rápido, muy fácil, reproductor de audio con Python


En la entrada anterior pudimos ver cómo con muy poco código fue posible obtener un simple pero poderoso navegador web con el lenguaje de programación Python, PySide (Los bindings de Qt, uno de los  frameworks gráficos del lenguaje C++) y poco más de 70 líneas de código. En esta entrega veremos cómo usando el diseñador de interfaces y algo de código podemos hacer un muy simple reproductor de audio, el cual será extendido en próximas entregas.
Primero que todo es necesario decir que Qt ofrece una herramienta para diseñar interfaces de usuario. Esta se llama QtDesigner y viene incluida en el instalador de la libreria PySide de windows (para los entornos linux hay que instalarlo a mano). Esta herramienta es muy útil, puesto que con ella podemos hacer la interfaz y luego exportarla al lenguaje que vayamos a usar para realizar la aplicación (en la actualidad Qt tiene bindings para varios lenguajes, entre ellos Java, Ruby, Python y Php, entre otros), además de proveer un sistema de enlace entre objetos y métodos mediante eventos (en Qt se habla de slots y signals), lo cual facilita en cierta manera la tarea del programador. Esta herramienta es una herramienta WYSIWYG, la cual nos permite arrastrar, soltar y acomodar hasta obtener la interfaz como se desea. A continuación la imagen de la interfaz gráfica del reproductor:


La interfaz gráfica contiene unos cuantos QLabel para mostrar información, un QLCDNumber para mostrar cuánto tiempo ha transcurrido, un par de botones y unos espaciadores para conservar las proporciones al cambiar el tamaño de la ventana. A pesar de que sería posible "compilar" la interfaz a el lenguaje nativo con herramientas como el pyside-uic no lo vamos a hacer.

Ahora vamos a ver el código Python:

#!/usr/bin/env python

from PySide import QtCore, QtGui, phonon, QtUiTools
from PySide.phonon import Phonon

class Reproductor(QtGui.QWidget):

    def __init__(self):
        super(Reproductor, self).__init__(parent=None)
        self.setWindowTitle("Python Simple Player")
        self.gridLayout = QtGui.QGridLayout(self)
        loader = QtUiTools.QUiLoader()
        file = QtCore.QFile("repro.ui")
        file.open(QtCore.QFile.ReadOnly)
        self.ui = loader.load(file, self)
        file.close()
        self.gridLayout.addWidget(self.ui, 0, 0, 1, 1)
        # seccion multimedia
        self.audioOutput = Phonon.AudioOutput(Phonon.MusicCategory, self)
        self.mediaObject = Phonon.MediaObject(self)
        Phonon.createPath(self.mediaObject, self.audioOutput)
        self.mediaObject.setTickInterval(1000)
        #
        self.ui.lcdAvance.display("00:00")
        QtCore.QObject.connect(
            self.ui.btnArchivo,
            QtCore.SIGNAL("clicked()"),
            self.openFile)
        QtCore.QObject.connect(
            self.ui.btnPlay,
            QtCore.SIGNAL("clicked()"),
            self.play)
        self.mediaObject.tick.connect(self.alAvanzar)
        self.mediaObject.stateChanged.connect(self.alCambiarEstado)

    def alAvanzar(self, tiempo):
        displayTime = QtCore.QTime(
            0, (tiempo / 60000) %
            60, (tiempo / 1000) %
            60)
        self.ui.lcdAvance.display(displayTime.toString('mm:ss'))

    def alCambiarEstado(self, new, old):
        if self.mediaObject.state() == Phonon.State.StoppedState:
            self.ui.btnPlay.setEnabled(True)
        elif self.mediaObject.state() == Phonon.State.PlayingState:
            self.ui.btnPlay.setText("||")  # .setEnabled(False)

    def play(self):
        if self.mediaObject.state() == Phonon.State.PlayingState:
            self.mediaObject.pause()
            self.ui.btnPlay.setText(">")
        else:
            self.mediaObject.play()
            #///////////////////////////////////
            meta = self.mediaObject.metaData()
            meta["TITLE"] = meta["TITLE"] if "TITLE" in meta else "Indefinido"
            meta["ARTIST"] = meta[
                "ARTIST"] if "ARTIST" in meta else "SinNombre"
            label = "{TITLE} by {ARTIST}".format(**meta)
            self.ui.lblNombre.setText(label)
            #///////////////////////////////////
            self.ui.btnPlay.setText("||")

    def openFile(self):
        fileName = QtGui.QFileDialog.getOpenFileName(
            self,
            u"Abrir Archivo",
            u"/",
            u"Archivos de Audio (*.mp3 *.wav *.ogg)")
        if fileName[1]:
            self.path = fileName[0]
            self.mediaObject.setCurrentSource(
                Phonon.MediaSource(self.path))
            self.ui.btnPlay.setText(">")
            self.ui.lblNombre.setText("...")
            self.ui.lcdAvance.display("00:00")

if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    rep = Reproductor()
    rep.show()
    sys.exit(app.exec_())

En el código anterior podemos ver cómo mediante el uso del modulo QtUiTools es posible usar la clase QUiLoader para cargar en tiempo de ejecución el archivo de interfaz gráfica (repro.ui), y obtenemos un objeto QWidget, el cual contiene toda la jerarquía de objetos que habíamos hecho en el diseñador de interfaces, los cuales quedan listos para ser usados a gusto. Después de esto acoplamos el QWidget obtenido mediante un gridLayout. Seguidamente creamos las instancias de la salida de audio (audioOutput) y del reproductor (mediaObject), los cuales son enlazados mediante la instrucción:
Phonon.createPath(self.mediaObject, self.audioOutput)
Esta instrucción enlaza el reproductor con la salida de audio. Después de esto se establece cada cuánto se va a lanzar una señal de actualización (es para que pueda medirse el tiempo transcurrido y hacer cosas de acuerdo a este) mediante el tickInterval, el cual se establece cada 1000 milisegundos (un segundo) y se conectan objetos como botones a los eventos correspondientes para que antes de finalizar el constructor se enlacen las señales del reproductor a los métodos encargados de modificar el avance y cambiar la etiqueta del botón de reproducción.
Los métodos siguientes se encargan de cambiar el valor de las etiquetas, de iniciar o detener la reproducción o cambiar el título de la pista.

 El código correspondiente esta en GitHub para quienes estén interesados.

lunes, 29 de julio de 2013

Entendiendo Javascript (V)


En el post anterior se intentó dar un vistazo general a el entorno de trabajo en JavaScript dentro de un navegador, mostrando cuáles eran sus propiedades principales, teniendo en cuenta que al iniciar la aplicación el entorno de trabajo está compuesto por todo lo que compone un objeto window, pero no sabemos mucho acerca de qué métodos o funciones podemos usar. A continuación veremos un poco de esto.
Recordemos, los procedimientos mostrados a continuación son métodos del objeto ventana y pueden ser invocados de manera directa puesto que el contexto de inicio de los scripts que se ejecutan en el navegador es la ventana misma.

  • alert(mensaje): Es uno de los procedimientos más usados, éste despliega un diálogo con un mensaje específico
  • close(): Cierra la ventana
  • confirm(mensaje): Lanza un diálogo de confirmación y dependiendo de la respuesta retorna true o false
  • open(url, nombre, parámetros, reemplazar):  Crea una nueva ventana en la cual carga la url, con el nombre y los parámetros especificados, y dependiendo del último valor la url especificada reemplazará la url de la ventana actual.
  • print(): Imprime el contenido de la página actual.
  • prompt(mensaje, valor): Crea un diálogo con una caja de texto, el diálogo tiene un mensaje especificado en el primer parámetro y como valor inicial el valor (valga la redundancia) especificado en el segundo parámetro.
  • setInterval(funcion_o_expr, milisecs): Llama a una función o evalúa una expresión cada cierto intervalo de milisegundos. se detiene cuando la función clearInterval(id) es llamada. Ésta retorna un identificador.
  • clearInterval(id): Detiene la ejecución periódica de la acción creada con setInterval a la que está asociada el id entregado.
  • setTimeout(): Llama a una función o evalúa una expresión después de un intervalo de tiempo especificado en milisegundos. Ésta retorna un identificador y es detenida por la función clearTimeout(id).
  • clearTimeout(id): Detiene la ejecución de la acción lanzada por setTimeout asociada al id entregado.
Muy bien, todo esto es muy bonito, pero, ¿Para qué podría usar todo esto?. A continuación vamos a hacer un pequeño ejemplo en el cual vamos a usar solo un par de los procedimientos que fueron descritos anteriormente. Vamos a hacer un cronómetro.

A continuación está el código HTML:

<html>
  <head>
    <title>Mi Cronometro</title>
    <style>
      #reloj {
        font-size:4em;
      }
    </style>
    <script src="crono.js"></script>
  </head> 
  <body>
    <script>
        var cronometro = new Cronometro();
    </script>
    <button onclick="cronometro.iniciar()">Inicio</button>
    <button onclick="cronometro.detener()">Detener</button>
    <button onclick="cronometro.reiniciar()">Reiniciar</button>
    

    <div id="reloj">
      0:0
    </div>
</body>
</html>

Y el código JavaScript:
function Cronometro(lugarCarga){
  var self = this;
  self.interval = 0;
  this.upd = function(){
    var secs = self.interval/100;
    var milis = self.interval%100;
    self.lugarCarga.innerHTML = Math.floor(secs)+":"+milis;
  }
  this.paso = function(){
    self.interval = self.interval + 1;
    self.upd();
  }
  this.iniciar = function(){
    self.lugarCarga = document.getElementById('reloj');
    self.id_intervalo = setInterval(self.paso,10);
  };
  this.detener = function(){
    clearInterval(self.id_intervalo);
  };
  this.reiniciar = function(){
    self.interval = 0;
    self.lugarCarga.innerHTML = "0:0";
  };
}


Pueden encontrar los códigos de ejemplo en GitHub.

viernes, 26 de julio de 2013

Muy rápido, muy fácil, navegador web con Python

Python es un lenguaje que por su simpleza y versatilidad ha llegado a ser usado en muchos y muy buenos proyectos. A continuación veremos en este post el código de un navegador web muy simple, con soporte para la mayoría de las características de HTML5. Para poder hacer esto usamos Python2.7 y PySide de 32 bits si el sistema operativo es Windows, si es Linux podemos instalarlo usando los repositorios inestables o de pruebas mediante el clásico apt-get así:

apt-get install python-pyside

Aquí vamos:
# -*- coding: utf-8 -*-
# Tested in Python2.7

from PySide import QtCore, QtGui
from PySide import QtWebKit
from PySide import QtNetwork


class Navegador(QtGui.QWidget):

    def __init__(self):
        # constructor de la clase
        super(Navegador, self).__init__(parent=None)
        self.setWindowTitle("Python Navigator")
        self.showMaximized()
        self.gridLayout = QtGui.QGridLayout(self)
        self.btnAtras = QtGui.QPushButton(self, text='atras')
        self.gridLayout.addWidget(self.btnAtras, 0, 0, 1, 1)
        self.btnAdelante = QtGui.QPushButton(self, text='adelante')
        self.gridLayout.addWidget(self.btnAdelante, 0, 1, 1, 1)
        self.label = QtGui.QLabel(u"Dirección", self)
        self.gridLayout.addWidget(self.label, 0, 2, 1, 1)
        self.txtUrl = QtGui.QLineEdit(self)
        self.gridLayout.addWidget(self.txtUrl, 0, 3, 1, 1)
        self.wvNavegador = QtWebKit.QWebView(self)
        self.gridLayout.addWidget(self.wvNavegador, 1, 0, 1, 4)

        QtNetwork.QNetworkProxyFactory.setUseSystemConfiguration(True)
        QtWebKit.QWebSettings.globalSettings().setAttribute(
            QtWebKit.QWebSettings.PluginsEnabled, True)
        QtWebKit.QWebSettings.globalSettings().setAttribute(
            QtWebKit.QWebSettings.JavascriptCanOpenWindows, True)
        QtWebKit.QWebSettings.globalSettings().setAttribute(
            QtWebKit.QWebSettings.DeveloperExtrasEnabled, True)

        QtCore.QObject.connect(
            self.txtUrl,
            QtCore.SIGNAL("returnPressed()"),
            self.cargarUrl)
        QtCore.QObject.connect(
            self.btnAtras,
            QtCore.SIGNAL("clicked()"),
            self.wvNavegador.back)
        QtCore.QObject.connect(
            self.btnAdelante,
            QtCore.SIGNAL("clicked()"),
            self.wvNavegador.forward)

        _url = "http://www.python.org"
        self.wvNavegador.load(QtCore.QUrl(_url))
        self.txtUrl.setText(_url)

    def cargarUrl(self):
        url = self.txtUrl.text()
        url = url if url.startswith(
            "http://") or url.startswith(
                "https://") else "http://{url}".format(
                    url=url)
        self.wvNavegador.load(QtCore.QUrl(url))


if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    nav = Navegador()
    nav.show()
    sys.exit(app.exec_())

Podemos ver que en el bloque de código anterior se crea la clase navegador, en la cual se crean los controles básicos (la caja de texto para la URL, botones de atrás y adelante, el espacio de navegación), después de esto se "empaquetan" por así decirlo en un gridlayout, el cual nos permite hacer que los controles se ajusten de manera dinámica cuando cambie el tamaño de la ventana. Después se habilitan los plugins del elemento mediante el cual se navega para que sea posible ver vídeos en youtube e inspeccionar elementos (muestra el DOM, los scripts y demás de manera muy similar a la de Google Chrome) mediante click derecho, luego se enlazan los botones al navegador mediante los eventos de click y la barra de direcciones al navegador mediante el evento returnPressed y después se carga la URL inicial ("http://www.python.org").
Finalmente se instancia los objetos necesarios para iniciar nuestro navegador.

Fácil, efectivo y contundente, un navegador muy simple con menos de 70 lineas de código.

Aquí esta el enlace al repositorio en GitHub (siéntanse libres de modificarlo) y abajo les dejo una imagen de como se ve.


jueves, 25 de julio de 2013

Consoleando (II)

Después de aprender lo básico es hora de aprender cosas más interesantes, scripts.

¿Qué es un Script?
Un script es un archivo que contiene una secuencia de órdenes que facilitan alguna labor (es un programa).

Ejemplo de un Script
A continuación veremos cómo se hace un script básico, saludo.sh . La labor de éste script es escribir "buenos dias", "buenas tardes" o "buenas noches", lo anterior dependiendo de la hora.
Entonces:

#!/bin/bash
# la linea anterior se pone para que el sistema operativo
# sepa con que interprete debe ejecutar el script

### programa: saludo.sh
let HORA=`date +%H` # capturamos la hora del dia
if [ $HORA -ge 4 ] && [ $HORA -lt 12 ]; then
    echo 'Buenos Dias!!!'
fi
if [ $HORA -ge 12 ] && [ $HORA -lt 18 ]; then
    echo 'Buenas Tardes!!!'
else
    echo 'Buenas Noches!!!'
fi
### fin programa

En este bloque de código podemos ver muchas de las interesantes cosas que tiene el lenguaje bash, uno de los lenguajes usados en las consolas Linux, éste es simple y potente, además nos permite usar comandos del sistema como date, crear variables mediante la orden let, extraer información de los comandos del sistema (una de las formas de hacer esto es mediante las comillas invertidas [ ` ], las cuales interpretan el comando que esté dentro de las comillas y retornan esa cadena convertida en valor, lo cual puede ser almacenado o usado en nuestro programa), usar condicionales ( if, else, case), operadores lógicos ( && y | | ), escribir cadenas mediante la orden echo y muchas más cosas.
Algo que en principio es extraño para quienes hacen scripts es que no entienden qué es -lt o -ge, estos son los operadores de comparación, a continuación los veremos en una tabla con sus significados:

comandosignificado
-lt menor que
-le menor o igual que
-eq igual que
-ge mayor o igual que
-gt mayor que
-ne diferente a


Y, ¿Qué hacer con ese código?
Este código se guarda en un archivo de texto, por ejemplo saludo.sh (uso la extensión sh porque es un archivo del lenguaje bash, que es a su vez una mejora de sh), y luego en la consola hago que éste se pueda ejecutar mediante la orden chmod así:
chmod +x saludo.sh

Y, ¿Cómo lo ejecuto?
Para ejecutarlo escribimos en la consola la ruta completa del archivo si estamos en una carpeta diferente a la del archivo, si estamos en la misma carpeta  anteponemos un punto, así:
# si no estamos en la misma carpeta
/home/andres/saludo.sh
# y si estamos en la misma carpeta
./saludo.sh