0% found this document useful (0 votes)
102 views22 pages

Programando For Todos 2

This document provides a summary of using Spring Batch to process large volumes of data in batch jobs. It discusses batch processing concepts like steps, readers, processors, writers and jobs. It then provides a code example of using Spring Batch to read voltage and time data from a CSV file, process it, and write it to an H2 database. The example sets up the project structure, defines entities, and configures the item reader, processor, writer and job to batch process the CSV data.

Uploaded by

Ariel Cupertino
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
102 views22 pages

Programando For Todos 2

This document provides a summary of using Spring Batch to process large volumes of data in batch jobs. It discusses batch processing concepts like steps, readers, processors, writers and jobs. It then provides a code example of using Spring Batch to read voltage and time data from a CSV file, process it, and write it to an H2 database. The example sets up the project structure, defines entities, and configures the item reader, processor, writer and job to batch process the CSV data.

Uploaded by

Ariel Cupertino
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 22

Programación para todos II

Batch Processing Large Data Sets with


Spring Boot and Spring Batch
Batch processing of data is an efficient way of processing large volumes of data where data is
collected, processed and then batch results are produced. Batch processing can be applied in
many use cases. One common use case of batch processing is transforming a large set of flat,
CSV or JSON files into a structured format that is ready for further processing.

In this article, I am going to demonstrate batch processing using one of the projects of Spring
which is Spring Batch. Spring Batch provides functions for processing large volumes of data
in batch jobs. This includes logging, transaction management, job restart (if a job is not
completed), job skip, job processing statistics, and resource management.

Let us look at how Spring Batch works in a nutshell.


Spring Batch overview

A step is an object that encapsulates sequential phase of a job and holds all the necessary
information to define and control processing. It delegates all the information to a Job to carry
out its task.

Spring Batch uses chunk oriented style of processing which is reading data one at a time, and
creating chunks that will be written out within a transaction. The item is read by ItemReader
and passed onto ItemProcessor, then it is written out by ItemWriter once the item is ready.
The Job Repository will be used to store the step execution periodically during the item
processing.

Let’s get into coding.


Setting up Project

Create a sample Spring Boot application. Here is my sample project structure.


Project Structure

In this article, I will be using sample data which represents voltage drop for a discharging
Capacitor. We will read this data from a CSV file and write it out to an in-memory database
which is H2.

Add the required dependencies to pom.xml.

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>

The CSV file Volts.csv contains two fields volt and time. Let us create a JPA entity called
Voltage. Note that this entity is just for the example. It is not production ready code.

package com.techshard.batch.dao.entity;import javax.persistence.*;


import javax.validation.constraints.NotNull;
import java.math.BigDecimal;@Entity
public class Voltage { @Id
@Column (name = "ID", nullable = false)
@GeneratedValue (strategy = GenerationType.IDENTITY)
private long id; @NotNull
@Column (name = "volt", precision = 10, scale = 4, nullable = false)
private BigDecimal volt; @NotNull
@Column (name = "time", nullable = false)
private double time; public Voltage() {
} public Voltage(final BigDecimal volt, final double time) {
this.volt = volt;
this.time = time;
} public long getId(){
return id;
} public BigDecimal getVolt(){
return volt;
} public void setVolt(final BigDecimal volt){
this.volt = volt;
} public double getTime(){
return time;
} public void setTime(final double time){
this.time = time;
}
}

Batch configuration
Let’s create a batch configuration class:

@Configuration
@EnableBatchProcessing
public class BatchConfiguration {
}

@EnableBatchProcessing enables Spring Batch features and provides a base configuration


for setting up batch jobs in an @Configuration class.

We need to include two components in the above class.

@Autowired
public JobBuilderFactory jobBuilderFactory; @Autowired
public StepBuilderFactory stepBuilderFactory;

JobBuilderFactory creates a job builder. Using StepBuilderFactory, Spring Batch will create
a step builder and will initialize its job repository and transaction manager.
Configuring ItemReader

We will now define ItemReader interface for our model Voltage which will be used for
reading data from CSV file.

@Bean
public FlatFileItemReader<Voltage> reader() {
return new FlatFileItemReaderBuilder<Voltage>()
.name("voltItemReader")
.resource(new ClassPathResource("Volts.csv"))
.delimited()
.names(new String[]{"volt", "time"})
.lineMapper(lineMapper())
.fieldSetMapper(new BeanWrapperFieldSetMapper<Voltage>() {{
setTargetType(Voltage.class);
}})
.build();
}

Here, we are creating FlatFileItemReaderBuilder of model Voltage.

name — Name of the ItemReader

resource — Specify path for the resource file to be read.

delimited — Builds delimited tokenizer.

names — Pass the fields that are to be read

lineMapper — Interface to map lines from file to domain object.

fieldSetMapper — Interface to map data obtained from a fieldset to an object.


Note that, we have passed custom lineMapper() above. Let us define that bean.

@Bean
public LineMapper<Voltage> lineMapper() { final DefaultLineMapper<Voltage>
defaultLineMapper = new DefaultLineMapper<>();
final DelimitedLineTokenizer lineTokenizer = new DelimitedLineTokenizer();
lineTokenizer.setDelimiter(";");
lineTokenizer.setStrict(false);
lineTokenizer.setNames(new String[] {"volt","time"}); final VoltageFieldSetMapper
fieldSetMapper = new VoltageFieldSetMapper();
defaultLineMapper.setLineTokenizer(lineTokenizer);
defaultLineMapper.setFieldSetMapper(fieldSetMapper); return defaultLineMapper;
}

In the custom lineMapper, we can specify the delimiter to be read from CSV file and also
used for reading string values into database specific datatypes. The VoltageFieldSetMapper is
defined as follows:

package com.techshard.batch.configuration;import com.techshard.batch.dao.entity.Voltage;


import org.springframework.batch.item.file.mapping.FieldSetMapper;
import org.springframework.batch.item.file.transform.FieldSet;
import org.springframework.stereotype.Component;@Component
public class VoltageFieldSetMapper implements FieldSetMapper<Voltage> { @Override
public Voltage mapFieldSet(FieldSet fieldSet) {
final Voltage voltage = new Voltage();
voltage.setVolt(fieldSet.readBigDecimal("volt"));
voltage.setTime(fieldSet.readDouble("time"));
return voltage; }
}

Configuring ItemProcessor

We will define the processor in Batch configuration as follows:

@Bean
public VoltageProcessor processor() {
return new VoltageProcessor();
}

We have defined a custom processor VoltageProcessor. Once the data is read, this processor is
used for processing the data such as data conversion, applying business logic and so on. This
is just an example. This custom processor may not always be required. It can be defined
depending on your application requirements.

package com.techshard.batch.configuration;import
com.techshard.batch.dao.entity.Voltage;import
org.springframework.batch.item.ItemProcessor;import java.math.BigDecimal;public class
VoltageProcessor implements ItemProcessor<Voltage, Voltage>{ @Override
public Voltage process(final Voltage voltage) {
final BigDecimal volt = voltage.getVolt();
final double time = voltage.getTime(); final Voltage processedVoltage = new
Voltage();
processedVoltage.setVolt(volt);
processedVoltage.setTime(time);
return processedVoltage;
}
}

ItemWriter

Once the data is processed, the data needs to be stored in database as per our requirement. We
will define a JdbcBatchWriter to insert data into database table. There is also JPA specific
JpaItemWriter which can be used with EntityManager.

@Bean
public JdbcBatchItemWriter<Voltage> writer(final DataSource dataSource) {
return new JdbcBatchItemWriterBuilder<Voltage>()
.itemSqlParameterSourceProvider(new
BeanPropertyItemSqlParameterSourceProvider<>())
.sql("INSERT INTO voltage (volt, time) VALUES (:volt, :time)")
.dataSource(dataSource)
.build();
}

Job and Step Configuration

We will now define a Step which will contain a reader, processor, and writer in the same way
we need a StepBuilderFactory, which will be used to inject in our Job() method.

@Bean
public Step step1(JdbcBatchItemWriter<Voltage> writer) {
return stepBuilderFactory.get("step1")
.<Voltage, Voltage> chunk(10)
.reader(reader())
.processor(processor())
.writer(writer)
.build();
}

Here, step1 is just a name of the Step which we can define. We can also specify chunk size in
Step configuration.

Finally, a Job is defined as follows:

@Bean
public Job importVoltageJob(NotificationListener listener, Step step1) {
return jobBuilderFactory.get("importVoltageJob")
.incrementer(new RunIdIncrementer())
.listener(listener)
.flow(step1)
.end()
.build();
}
Note that we have passed NotificationListener that extends Spring Batch’s
JobExecutionListenerSupport. It can log results before or after job execution. Here, we have
only defined afterJob(). JobExecutionListenerSupport also provides beforeJob() to log any
information before the job execution.

package com.techshard.batch.configuration;

import com.techshard.batch.dao.entity.Voltage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.listener.JobExecutionListenerSupport;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

@Component
public class NotificationListener extends JobExecutionListenerSupport{

private static final Logger LOGGER =


LoggerFactory.getLogger(NotificationListener.class);

private final JdbcTemplate jdbcTemplate;

@Autowired
public NotificationListener(final JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}

@Override
public void afterJob(final JobExecution jobExecution) {
if(jobExecution.getStatus() == BatchStatus.COMPLETED) {
LOGGER.info("!!! JOB FINISHED! Time to verify the results");

jdbcTemplate.query("SELECT volt, time FROM voltage",


(rs, row) -> new Voltage(
rs.getBigDecimal(1),
rs.getDouble(2))
).forEach(voltage -> LOGGER.info("Found <" + voltage + "> in the database."));
}
}
}

Before we run the application, we will enable H2 (in-memory) console in


application.properties.

spring.datasource.url=jdbc:h2:mem:batchdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.h2.console.enabled=true

Additionally, I have also configured Aspect using Spring AOP to measure the time taken by
batch execution.

package com.techshard.batch;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class TracePerformanceAspect {

private final Logger logger = LoggerFactory.getLogger(TracePerformanceAspect.class);

@Around ("execution(* com.techshard..*.*(..)))")


public Object logTracePerformanceAspect(ProceedingJoinPoint joinPoint) throws
Throwable {

MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();

//Get intercepted method details


String className = methodSignature.getDeclaringType().getSimpleName();
String methodName = methodSignature.getName();

long start = System.currentTimeMillis();

Object result = joinPoint.proceed();


long end = System.currentTimeMillis();

//Log method execution time


logger.info("Execution time of " + className + "." + methodName + " :: " + (end - start)
+ " ms");

return result;
}
}

Running the Application

Run the Spring Boot application. Once the application is started, login to H2 console using
link http://localhost:8080/h2-console/ . Then, you will get a login screen as below.
H2 Console Login screen
Once we login, we will be able to see the table Voltage and all the tables created by Spring
Batch. In these tables, we will find all the details about job execution such as job name,
status, id and so on.
H2 Database
Conclusion

This article just scratched the surface of Spring Batch in general. The example used in this
article is not production ready code. You can define job configuration depending on your
project requirements. I hope you enjoyed this article. Let me know if you have any comments
or suggestions.

The complete code can be found on my GitHub repository.

This article was originally published on Techshard.com.

https://github.com/swathisprasad/batch-processing-large-datasets-spring
https://techshard.com/2019/07/22/batch-processing-large-data-sets-with-spring-boot-and-
spring-batch/

Introduction to Spring Batch

Now we tend to go more towards automated systems that are composed of several elements
designed to perform a set of scheduled tasks. They simplify, secure and make repetitive and
operational tasks easier. These processes are complex and with large volumes of information
without human interaction(read a file, process data, export data to a database, etc.).
Imagine our application receive every hour , from a file, a set of users informations from a
file to process, generate a password for every user in the file and insert it in a database.
In my mind I thought to make a shell script or develop a program from scratch to do the
process (recover, loop, read, process, transform, insert, …). But within this mode of treatment
the risk is enormous. This may take longer, error handling is to be expected, manage
rollbacks , not reliable because of the possibility of having an OutOfMemoryError, … I was
not ready to reinvent the wheel( Don’t Repeat Yourself they said). Thus, i started looking for
solutions in Internet and suddenly i come across a framework that allows to repeat a
treatment on a set of large volumes of data without human intervention. It was Spring Batch
and for me it was also the opportunity to test Spring and its ecosystem. Let’s go!
Spring batch ???
Spring Batch is a lightweight, comprehensive batch framework designed to enable the
development of robust batch applications vital for the daily operations of enterprise systems.
Spring Batch is not a scheduling framework. It provides reusable functions that are essential
in processing large volumes of records, including logging/tracing, transaction management,
job processing statistics, job restart, skip, and resource management.
Key Concepts
See the Batch Domain for more details.
• Job : A batch job composed of a sequence of one or more Steps.
• JobInstance :an instance of a Job configured with parameters (requested, for a
specific date for example). A collection of JobExecutions.
• Step : An independent, discrete unit of work in a Job. A simple Step might load data
from a file into the database, but may be more complex.
• JobExecution : An single attempt of a Job run (may be in progress, succeeded, or
failed)
• StepExecution : A single attempt of a Step, associated with a JobExecution (may be
in progress, succeeded or failed)
• JobRepository : Persistent storage for maintaining the Batch Domain model and
associated state
• JobExecutionListener : Extension point for customizing JobExecution events.
• StepExecutionLister : Extension point for customizing StepExecution events.
• Remote Chunking, Partitioning* : Patterns for scalable distributed batch processing,
see the docs for details.
•Among others we can see as advantages
• Less coding
• More unit tests & integrations
• He takes care of the increase in load
• And many others ( see HERE)

Use case Spring batch

A batch program usually performs some number of recurring actions:

Read a large number of records in a file or database,


Sometimes do specific processing on the data (modification, call web service, etc …),
Write / Insert processed data into a database or file.

Another example of use: The payment of salary in a company

1 — At the end of the month, the company must send a salary to the respective accounts of
its employees.

2 — Do the processing of pay slips.

3 — Sending emails to staff for mass communication.

4 — Generate automated reports on a daily, weekly or monthly basis.

5 — Run the stream automatically without human intervention.

Technical Objectives

As a developer also we see a considerable contribution in our work with the use of spring
batch.

Batch developers use the Spring programming model: concentrate on business logic and let
the framework take care of infrastructure.
Clear separation of concerns between the infrastructure, the batch execution environment,
and the batch application.
Easy to configure, customize, and extend services, by leveraging the spring framework in
all layers.
All existing core services should be easy to replace or extend, without any impact to the
infrastructure layer.
Provide a simple deployment model, with the architecture JARs completely separate from
the application

Spring Batch architecture

This layered architecture highlights three major high-level components: Application, Core,
and Infrastructure.
Application

The application contains all batch jobs and custom code written by developers using Spring
Batch.
Code

The Batch Core contains the core runtime classes necessary to launch and control a batch job.
It includes implementations for JobLauncher, Job, and Step.
Infrastructure

This infrastructure contains common readers and writers and services (such as the
RetryTemplate), which are used both by application developers(readers and writers, such as
ItemReader and ItemWriter) and the core framework itself (retry, which is its own library).
Sample example

Here is a quick overview of how we plan to process our received files from .

1- At first, data is read from a file using the ItemReader that is part of Spring Batch.

2- The data is then passed to the processor (ItemProcessor) for processing the data according
to the needs of the enterprise. We have to format the date to adapt it to the database.

3- The processed data that is now modified is transmitted in the database for writing
(ItemWritter).

NB : the data source can be a database, file, queue, and so on.


Error management in spring batch

Spring batch also allows us to handle errors on processing

Skip non-blocking errors (skip). Sometimes we do not need to stop stuff if we encounter
some errors.
Start a job again (retry). The database may be unavailable at a temporary moment.
Sometimes we need to retry the process.
Restart a batch (restart). After an error we are able to restart it.

Demo

For example i set up a small application that allows us to recover data from a file, do certain
treatments before inserting it into a database. Using Spring Batch Flat file reader to read CSV
file and Jdbc Batch Item Writer to write MySQL Database. After the treatment we can do
other actions depending on the result of the job. If job success we can send a notification
mail. If not we can retry to lunch the job or do something else.

INPUT
OUTPUT

See the repo for more details : https://github.com/tonux/file-processor

https://github.com/tonux/file-processor
https://medium.com/@ndongotonuxsamb/introduction-to-spring-batch-41b5e11fd5f5

Linux Shell
Esto comúnmente es lo que se le llama en los Sistemas Operativos, La Consola. Con las
versiones nuevas de Microsoft Windows se ha dejado un poco atrás, con esto de que hay
asistentes, gráficos para facilitar el trabajo al usuario, pero cuando no existía estas cosas,
antaño se usaba lo que es el Intérprete de Comandos. Básicamente es el infierno de los
usuarios de interfaces gráficos, pero en realidad de esta forma tienes más control y más
opciones de configuración. Que sí, que es más feo, todo en texto plano, pero no deja de ser
eficiente, efectivo y lo mejor de todo, apenas consume memoria ya que no usa gráfico
alguno.

¿Que es Shell?
Básicamente un script de shell es un archivo de texto simple con listas de comandos que se
ejecutan de forma secuencial. Se compone de procedimientos, variables, funciones,
condiciones, bucles, arrays…etc, como cualquier otro lenguaje de programación, pero
orientado a la consola de un sistema operativo. Existen diferentes tipos de interpretes:
• Bourne Shell o sh. Se creó en 1977 y se convirtió en el intérprete por defecto en las
primeras versiones de UNIX.
• Korn Shell. Se creó a principios de los 80 para el proyecto GNU.
• Bash. Se creo en 1987 también para el proyecto GNU. Muchas ideas fueron basadas
del Korn Shell. Actualmente es el principal intérprete en las mayoría de las
distribuciones Linux que hay en la actualidad.
• Zsh. Se creó en 1990. En principio se diseñó para poder usarlo de forma interactiva.
• Todos son buenos intérpretes para usar, algunos con sus pros y sus contras, pero yo
me voy a centrar un poco en bash, que es el que se usa comúnmente en las
distribuciones Linux más usadas.

• Información de Shell.
• echo $SHELL # Indica el shell que estamos usando.
echo $BASH_VERSION #Indica la versión de shell bash.
whereis bash # Indica donde está instalado shell bash.
cat /etc/shells # Indica todos los shell que hay
instalado.
chsh -s /bin/bash # Poner por defecto shell bash.

• Creando mi primer Script.


• #!/bin/bash
# Esto es un comentario.

echo "Hola mundo"


• Se debe siempre empezar con #!/bin/bash. Esto le indica al sistema cual es el
intérprete que debe usar.
• Los comentarios es algo muy imporante en cualquier lenguaje de programación. En
bash se ponen con al signo #.
• echo. Instrucción que muestra por pantalla información, ya sean variables, números o
cadenas.

• ¿Como se ejecuta un Script?


• Los Script se pueden ejecutar de las siguientes formas:
• bash <nombre del script>.
• ./<nombre del script>. Este forma tiene un inconveniente, hay que darle permisos de
ejecución al archivo con el comando chmod o no se ejecutará. La instrucción sería la
siguiente; chmod +x <nombre del script>
• source <nombre del script>.

Son trozitos de memoria a la cual asignamos un nombre para usarla en el procedimiento. El


nombre de una variable sólo puede contener letras a-z A-Z, números del 0–9 o el carácter de
guión bajo (_).
¿Como se definen?.
Las varibles se definen sin nada especial, simplemente se pone el nombre de la variable el
valor que queremos asignarle.
var=”mi texto”
var=0125
¿Como accedo a su valor?
La forma de acceder es anteponiendo el signo $ de la variable.
#!/bin/bash
var=”mi texto”
echo $var
Shell tiene una forma de evitar que se pueda modificar el valor de una variable, es decir,
ponerlo como sólo lectura.
#!/bin/bash
var=”mi texto”
readonly var
echo $var
Si ahora intentaramos hacer una asignación, nos dará un error indicando que no se puede
modificar el valor de la variable.
Ya no voy usar la variable ¿Que hago con ella?
Si no necesitamos alguna variable, podemos destruirla de forma que ya no se podrá acceder
al valor de ésta. Hay que tener en cuenta que no se puede usar esta instrucción en variables
definidas como sólo lectura.
unset <nombre variable>
Tipos de variables.
• Variables locales. Son las que se definen única y exclusivamente en el script que se
está ejecutando, no pudiendo ser modificada por ningún otro script o procedimiento.
• Variables globales. Son las que se definen de forma global, de modo que puede ser
modifciada por otros procedimientos en cualquier momento.
• Variables especiales.
• $$. Muestra el número de proceso del sistema que tiene el shell, es decir el PID.
• $0. Muestra el nombre del script que se está ejecutando.
• $n. El valor de n es el número de argumento que le pasamos al script, de forma que si
hay varios parámetros lo definiríamos como $1, $2, $3, en el caso de que haya 3
parámetros.
• $#. Muestra el número total de parámetros que le pasamos en el script.
• $*. Muestra el valor de todos los parámetros que le pasamos al script.
• $@. Muestra el valor de todos los parámetros que le pasamos al script.
• $?. El estado de salida del último comando ejecutado. Shell devuelve un estado para
saber si es correcto la ejecución o no, es decir, mostrará un 0 si ha ido todo bien y un
1 si ha fallado o ha tenido errores
• $!. El número de proceso del último comando que está en segundo plano.
• Veamos un ejemplo:
• #!/bin/bash
echo “Nombre del script: $0”
echo “Parámetro1 : $1”
echo “Parámetro2 : $2”
echo “Valores de los parámetros: $@”
echo “Valores de los parámetros: $*”
echo “Total parámetros : $#”
echo $?
• Al ejecutar ./script.sh Benezor 79
• Nombre del script : ./script.sh
Parámetro1 : Benezor
Parámetro2 : 79
Valores de los parámetros: Benezor 79
Valores de los parámetros: Benezor 79
Total Total parámetros: 2
0
• Variables Arrays.
• Este tipo de variables es una forma de almacenar varios conjuntos de valores con un
sólo nombre. La forma de definirlo es la siguiente:
• #!/bin/bash
array=(ismael lourdes carlos jesus rosario)
echo “El primer elemento es: ${array[0]}”
echo “El segundo elemento es: ${array[3]}”
• Este ejemplo tenemos una array de 5 elementos (0–5). Asignamos a cada elemento un
valor y mostramos el valor del primero y el cuarto, para ver así como se accede a
éstos desde una array.
• Vamos a mostrar todos los elementos:
• echo “Todos los elementos son: ${array[*]}”
echo “Todos los elementos son: ${array[@]}”

En esta parte vamos hablar de los distintos operadores que existen en la programación;
ariméticos, lógicos, booleanos, string y los file test.
Aritméticos.
• +. Asignación.
• -. Substracción.
• *. Multiplicación.
• /. División
• %. Módulo o resto de una división.
• =. Asignación.
• ==. Comparación de números.
• !=. Negación.
• Algunos ejemplos:
• valor=`expr $a + $b`
valor`expr $a — $b`
valor `expr $a \* $b`
[ $a == $b ]
• Hay que tener en cuenta una cosa, Shell es un poco especial y debemos separar
siempre los operadores de las variables o dará un error;
• ¿Que es eso de expr?. Se utiliza para guardar el resultado de una expresión en una
variable.
• Relacionales.
• Este tipo de operadores se utilizan sólo y exclusivamente para cadena de carácteres.
• -eq. Compara si son iguales dos cadenas. Si lo son devuelve un true.
• -ne. Compara si son iguales dos cadenas. Si no lo son devuelve un true.
• -gt. Compara si la cadena de la izquierda es mayor que el de la derecha. Si es así
devuelve un true.
• -lt. Compara si la cadena de la izquierda es menor que el de la derecha. Si es así
devuelve un true.
• -ge. Compara si la cadena de la izquierda es mayor o igual que el de la derecha. Si es
así devuelve un true.
• -le. Compara si la cadena de la izquierda es menor o igual que el de la derecha. Si es
así devolverá un true.
• Booleanos.
• !. Niega una comparación.
• -o. Se utiliza para condiciones compuestas. Si una de las dos se cumple devuelve un
verdadero. [ $a -lt 20 -o $b -gt 100 ] .
• -a. Se utiliza para condiciones compuestas. Si se cumplen las dos condiciones a la vez
devuelve un true. [ $a -lt 20 -a $b -gt 100 ].
• String.
• =. Compara los valores y si son iguales devuelve un true.
• !=. Compara los valores y si es lo contrario que la expresión devuelve un true.
• -z. Compara si la longitud del valor es 0 y si lo es devuelve un true.
• -n. Compara si la longitud del valor es distinta de 0. Si es así devuelve un true.
• str. Compara si la cadena está vacia, si no está vacia devuelve un true.
• Files.
• Este tipo de operadores sirve para saber las propiedades dadas a un archivo en Linux,
es decir, los permisos de lectura, escritura y ejecución.
• -b file. Establece si el archivo es referente a un dispositivo del sistema, es decir,
perteneciente a /dev.
• -c file. Archivos especiales de tipo carácter.
• -d file. Que sea un directorio o carpeta.
• -f file. Que sea un archivo ordinario, es decir, que no sea ni un directorio ni archivo
especial.
• -g file. Comprueba que tenga activo el SGID, es decir, todo archivo que tenga activo
el SGID, al ser ejecutado, tendrá los privilegios del grupo al que pertenece.
• -k file Comprueba si tiene activo el sticky bit.¿Esto que es?. Cuando este bit está
activo, hace que un usuario sólo pueda borrar los ficheros que son de su propiedad en
dicho directorio.
• -p file Comprueba que el archivo sea named pipe.
• -t file Comprueba si el descriptor de archivo está abierto y asociado a una terminal.
• -u file. Comprueba si el archivo tiene establecido su SUID. El bit SUID activo en un
archivo significa que el que lo ejecute va a tener los mismos permisos que el que creó
el archivo
• -r file. Comprueba que el archivo tenga permisos de lectura.
• -w file. Comprueba que el archivo tenga permisos de escritura.
• -x file. Comprueba que el archivo tenga permisos de ejecución.
• -s file Comprueba que el archivo tiene un tamaño mayor de 0.
• -e file Comprueba que el archivo existe. En el caso que sea un directorio el sistema lo
dará por válido.

Las condiciones son algo muy esencial en cualquier lenguaje de programación, dependiendo
de lo que pase a lo largo de un procedimiento, escogeremos un camino u otro. Veamos como
funciona:
if [ expression ]
then
instrucciones
fi
Cuando se cumple y no se cumple:
if [ expression ]
then
instrucciones cuando se cumple la condición.
else
instrucciones cuando no se cumple la condición
fi
Cuando son muchos if…else anidados:
if [ expression 1 ]
then
instrucciones
elif [ expression 2 ]
then
instrucciones
elif [ expression 3 ]
then
instrucciones
else
instrucciones
fi

Bucles.
Los bucles es una instrucción también muy usada e importante en la programación, ya que
permite crear bucles de instrucciones tantas veces como nos haga falta y así evitar repetir
mucho código.
While.
Este tipo de bucle hace las instrucciones que vienen dentro hasta que no se cumpla la
condicíon, es decir, lo va hacer mientras que la condición se cumpla. Veamos como funciona:
while command
do
instrucciones
done
Un ejemplo:
#!/bin/bash

a=0

while [ $a -lt 12 ]
do
echo “El valor de a es: $a”
a=`expr $a + 1`
done
En este ejemplo hacemos el bucle hasta que sea mayor de 11 o 12 y muestra el valor de a. Es
decir, el resultado será algo así; 0 1 2 3 4 5 6 7 8 9 10 11 y en el 12 sale del bucle.
FOR.
El bucle for funciona en listas de elementos. Repite un conjunto de instrucciones para cada
elemento en una lista.
for var in elemento1 elemento2 ... elementoN
do
instrucciones por cada elemento
done
Un ejemplo:
#!/bin/bash

for var in 0 1 2 3 4 5 6 7 8 9
do
echo $var
done
¿y que pasaría si fueran 300 elementos? Sería un poco pesado poner 300 elementos en el for.
Para evitar eso podemos usar la instrucción seq:
#!/bin/bashfor var in $(seq 0 9)
do
echo $var
done
Until loop.
Este tipo de bucle se usa cuando queramos que haga el bucle mientras las condición no se
cumpla. Veamos como se usa:
until command
do
instrucciones
done
Veamos un ejemplo:
#!/bin/bash

a=0

until [ ! $a -lt 12 ]
do
echo $a
a=`expr $a + 1`
done
El bucle lo va a hacer mientras que no se cumpla la condición, es decir, negar que a sea
menor de 12 quiere decir que es mayor o igual de 12. Como a no es mayor e igual de 12, hace
instrucciones que hay dentro. El bucle se acabará cuando sea 12.
Select.
Este tipo de bucle proporciona una manera fácil de crear un menú numerado desde el cual los
usuarios pueden seleccionar opciones. Veamos como funciona:
select var in opcion1 opcion2... opcionN
do
instrucciones
done
Veamos un ejemplo:
#!/bin/bash

select opcion in 1 2 3 4 5 6 none


do
case $opcion in
1|2|3)
echo "Has seleccionado entre los 3 primeros"
;;
4|5|6)
echo "Has seleccionado entre los 3 últimos"
;;
none)
break
;;
*) echo "ERROR: No has seleccionado nada"
;;
esac
done
Control del Bucle.
Existen momentos concretos en los que necesitemos parar un bucle para que no continúa o
que se salta parte de éste. Existen dos instrucciones que nos permiten hacer estas tareas;
Break y Continue.
Break. Esta instrucción sirve para romper el bucle de forma tajante, es decir, finaliza el
procedimiento repetitivo y se va la línea de código siguiente. Un ejemplo:
#!/bin/bash

a=0

while [ $a -lt 10 ]
do
echo $a
if [ $a -eq 5 ]
then
break
fi
a=`expr $a + 1`
done
echo “El bucle ha terminado en la posición $a”
En este ejemplo vamos hacer un bucle del 0 al 10. Pero cuando llega a 5 mediante la
condición, hace un break y se sale de bucle y echa la siguiente línea de código después de
bucle.
Continue. Esta instrucción funciona muy parecida a break, la diferencia está que no rompe el
bucle entero, si no la iteración y pasa a la siguiente en el bucle. Veamos un ejemplo:
#!/bin/bash

NUMS="1 2 3 4 5 6 7"

for NUM in $NUMS


do
Q=`expr $NUM % 2`
if [ $Q -eq 0 ]
then
echo "El numero es par!!"
continue
fi
echo "El número es impar"
done
Este ejemplo creamos un bucle con for, que comprenderá los números del 1 al 7.
Simplemente queremos averiguar si es par o impar, es decir, si el resto de dividir cada
número entre 2 es 0.
En cuanto entre en la condición y el resultado sea 0, muestra un mensaje de que es par. Como
sólo es en ese caso, usamos un continúa. El programa lo que hace es evitar el código que hay
después del If y no muestra nada, continuando con el siguiente número del For.

El shell realiza una sustitución cuando encuentra una expresión que contiene uno o más
caracteres especiales. Veamos un ejemplo:
#!/bin/basha=10
echo -e "Value of a is $a \n"
En este ejemplo, simplemente mostramos el valor de a.
La opción -e sirve para que nos de la interpretación de los caracteres espaciales que hay en la
barra invertida (\n).
• \n. Nueva línea.
• \\. Muestra el carácter de barra invertida como texto.
• \a. Muestra un pitido de alerta.
• \b. Retroceso.
• \c. Suprime línea nueva.
• \r. Retorno de carro.
• \t. Pestaña horizontal.
• \v. Pesteña vertical.
• Shell también nos permite guardar el resultado de la ejecución de comandos,
simplemente metiendo el comando entre comillas inversas:
• #!/bin/bashDATE=`date`
echo "Date is $DATE"#Incluso varios comandos a la vez
separados por comas.
UP=`date ; uptime`
echo "Uptime is $UP"
• Sustitución de Variables.
• La sustitución de variables permite al usuario poder modificar el contenido de éstas
según su estado:
• ${variable}. Sustituye el valor de variable.
• ${variable:-”mensaje”}. Si la variable es nula o no tiene valor, lo sustituirá por
“mensaje”, pero en ningún caso modificará el valor de variable. Se suele utilizar para
mensajes de errores.
• ${variable:=”mensaje”}. Si la variable es nula o no tiene valor, se guardará por
defecto el valor que pongamos después del igual.
• ${variable:?menaje}. Si la variable es nula o no tiene valor, se imprirá lo que
pongamos después de la interrogación.
• ${variable:+palabra}. Si la variable se establece, es sustituido por palabra pero el
valor de variable no se modificará en ningún caso.
• #!/bin/bashvar=1echo ${var:-"No tiene valor"}
echo "1 - El valor es ${var}"echo ${var:="No tiene
valor"}
echo "2 - valor es ${var}"unset var
echo ${var:+"Por Defecto"}
echo "3 - El valor es $var"var="Otro valor"
echo ${var:+"Tiene valor"}
echo "4 - El valor es $var"echo ${var:?"Muéstrame este
mensaje"}
echo "5 - El valor es ${var}"
• Si no tuviera valor mostraría “No tiene valor”
• Si no tuviera valor guardaría en la variable “No tiene valor”.
• Si no tuviera valor o no existiera guardaría en la variable “Por Defecto”
• Si tiene valor mostraría el mensaje “Tiene valor”.
• Si no tiene valor o no existe mostraría el mensaje “Muéstrame este mensaje”.

• Metacaracteres.
• Shell proporciona varios caracteres que tienen un significado especial al usarlos en
cualquier Script, es decir, son como reservados por el propio sistema para realizar
ciertas funciones especiales.
• Un ejemplo claro puede ser el signo ? . Se utiliza para referirnos a un sólo carácter
cuando se listan archivos o se busca por algún patrón. También le pasa al signo *, que
lo utilizamos para referirnos a una cantidad indeterminada de caracteres a la hora de
buscar o listar archivos.
• Aquí hay una lista de la mayoría de los caracteres:
• * ? [ ] ' " \ $ ; & ( ) | ^ < > new-line space tab
• Algunos ejemplos:
• #!/bin/sh

echo Hola \; Ismael


echo "I have \$1200"
• Si ejecutamos este script el resultado sería el siguiente:
• Hola; Ismael
I have $1200
• El truco para que el sistema no interprete los caracteres especiales ; y $ está en la
barra invertida \. Ésta hace que se olvide de que son metacaracteres y muestra el
propio signo que estamos utilizando como un texto.
• Si vamos a utilizar muchos caracteres especiales, es muy pesado poner una barra
invertida a cada una, la solución estaría poner todo entre comilla simples y el sistema
lo interpretará como si pusieramos una barra invertida a cada uno de ellos:
• echo '<-$1500.**>; (Estás seguro?) [s|n]'
• Si queremos que muestre variables y que interprete bien el $, debemos usar las
comillas dobles:
• variable=Ismael
echo "$variable <-\$1500.**>; [ as of (`date +%m/%d`) ]"
• Las comillas dobles quita el significa especial que le da el sistema excepcionando los
siguientes:
• $
\$
\'
\"
• También podemos guardar el resultado de comandos del sistema en una variable, de
forma que podamos imprimir toda la información del comando:
• DATE=`date`
echo "La fecha de hoy es: $DATE"
• Para indicarle al sistema que es un comando, debemos especificárselo con las
comillas invertidas.

Cuando ejecutamos un comando cualquiera en una consola, normalmente te muestra los


resultados por la salida por defecto, es decir, la pantalla. Se puede desviar fácilmente a un
archivo si lo deseamos, a esto se le llama redireccionamiento de salida. Unos ejemplos:
who > usuarios
echo ismael >> usuarios
El truco de todo esto está en estos caractereres especiales:
• >. Redirecciona la salida por defecto del comando who a un archivo llamado usuarios.
Si existiera el archivo borraría su contenido y sólo añadiría el último resultado.
• >>. Redirecciona la salida por defecto hacia el archivo usuarios. En este caso al usar
doble redireccionamiento no borra el archivo si existiera, simplemente añade un
resultado más al contenido que hubiera ya dentro. Si no existe el archivo también lo
crea.
• Del mismo modo que la salida de un comando se puede redirigir a un archivo,
también se puede hacer lo contrario, es decir la entrada de un comando desde un
archivo. Así como el caracter mayor que (>) se usa para redireccionar la salida, la
entra se hace con el menor que (<).
• Vamos hacer un ejemplo. Lo que queremos es contar el número de líneas de un
archivo mediante esta forma:
• $ wc -l < users
• Simplemente le estamos dirigiendo el archivo usuarios al comando wc para que nos
cuente las líneas que contenga.
• También podemos redirigir los errores producidos hacia un archivo con el parámetro
2:
• $ cat < usuarios >usuariob 2> errores
• Con el parámetro 2 controlamos que donde se muestras los errores y en este caso
cambiamos la salida por defecto a un pequeño archivo llamado errores.
• Ocurre veces que nos puede interesar que no se muestren mensajes de ningún tipo en
la consola. Para realizar esta acción se redirecciona todo a /dev/null:
• $ gcc *.cpp > /dev/null 2 > /dev/null
• Delimitadores. Esto se suele usar para volcar código de un script o otro de forma que
le ponemos un delimitador indicándole hasta donde queremos que finalice tal
volcado. Un ejemplo:
• #!/bin/bash

cat << EOF


Una frase de ejemplo
Otra frase de ejemplo
vale, ya es esta la última frase de ejemplo.
EOF
• En este ejemplo el delimitador lo he llamado EOF, se puede llamar como queramos.
Le indicamos que muestre el texto por la salida por defecto hasta que encuentre el
delimitador, si hubiese más texto depués lo ignoraría.

Las funciones funcionan exactamente igual que los script, la diferencia está en que lo puedes
llamar desde cualquier lugar, ya que se cargan directamente en el entorno del intérpretes de
comandos. Son muy similares a las subrutinas, procedimientos y funciones en otros lenguajes
de programación. Su sintáxis básica es la siguiente;
function nombre_funcion() {
lista de comandos
}
Vamos con un ejemplo muy básico para ver como funciona.
#!/bin/bash# Creamos la función.
function hola() {
echo "Hola Ismael, este es mi primer ejercicio de funciones"
}
A la hora de llamar al procediendo
#Llamamos al procedimiento con el nombre de la función
hola
Las funciones son muy eficientes a la hora de trabajar, ya que podemos usarlas en cualquier
momento, en cualquier lugar, la única pega que tiene es que se deben cargar en memoria
todas las funciones para usar esa ventaja. Aunque en la actualidad con la cantidad de
memoria que usan los ordenadores, no debería preocuparnos, pero bueno, por eficacia y
eficiencia no deberíamos malgastar memoria aunque sea mucha cantidad. Para ver todas las
funciones que tenemos en el entorno del intérprete de comandos se ejecuta:
declare -F
Si queremos borrar una función del entorno de trabajo ejecutamos lo siguiente:
unset -f nombre_funcion
Para definir una función sólo basta escribirla directamente en la consola o mediante un script,
de forma que cuando se ejecute se carga en memoria.
Las funciones también pueden devolver valores con la instrucción “return”, veamos un
ejemplo:
#!/bin/bash

# Definimos la función
function hola () {
echo "Hola $1"
return 25
}

# Llamo a la función y le pongo un parámetro, mi nombre.


Hola Ismael

# Guardo el valor del comando ejecutado, que en este caso es


return.
devuelto=$?

echo "El valor del return es is $devuelto?"

Aquí algunos comandos para redes que sería interesante conocer:


Ping. Comprueba el estado de la conexión de un equipo. Lo que realiza es enviar un paquete
y ver cuanto tiempo tarda en responder el equipo remoto.
ping -c 4 www.duckduckgo.com
Traceroute. Traza el camino del envío de un paquete, es decir, te dice la máquina por la que
pasa hasta llegar a su destino.
traceroute www.duckduckgo.com
Netstat. Muestra toda la información de las conexiones de red, es decir, realiza una
estadística de toda la información que entra y sale de la red.
netstat -a
Ifconfig. Muestra información de red, así como interfaces, IP, MAC, DNS, Puertas de
Enlaces e incluso configurar la conexión a nivel de IP.
ifconfig #Muestra toda la información posible de los interfaces de red.ifconfig eth0
192.168.1.1 netmask 255.255.255.0 #Configura para el interfaz eth0 una IP y una Máscara de
Subred.ifconfig eth0 down #Desactiva el interfaz eth0.ifconfig eth0 up #Activa de nuevo el
interfaz eth0.
Iwconfig. Muestra la información de red pertinente a los interfaces inalámbricos.
iwlist wlan0 scan #Busca redes inalámbricas cerca mediante el interfaz wlan0.iwconfig
wlan0 essid "MI RED" key CONTRASEÑA #Configura un interfaz inalámbrico para
conectarse a un punto de acceso llamado "MI RED" con su correspondiente contraseña.
Dhclient. Se utiliza para conectarse de forma dinámica a una red, es decir, le asigna una
dirección IP automáticamente al conectarse.
dhclient wlan0. #Asigna automáticamente una IP al interfaz wlan0.
Nslookup. Muestra el nombre del servidor y la dirección IP de un nombre de dominio.
nslookup www.google.es #Muestra el nombre del servidor y la dirección ip de
www.google.es.

URL author
https://medium.com/@benezor79

You might also like