1 |
yoswink 07/11/02 14:41:57 |
2 |
|
3 |
Added: l-sed1.xml l-sed2.xml l-sed3.xml |
4 |
Log: |
5 |
New translation |
6 |
|
7 |
Revision Changes Path |
8 |
1.1 xml/htdocs/doc/es/articles/l-sed1.xml |
9 |
|
10 |
file : http://sources.gentoo.org/viewcvs.py/gentoo/xml/htdocs/doc/es/articles/l-sed1.xml?rev=1.1&view=markup |
11 |
plain: http://sources.gentoo.org/viewcvs.py/gentoo/xml/htdocs/doc/es/articles/l-sed1.xml?rev=1.1&content-type=text/plain |
12 |
|
13 |
Index: l-sed1.xml |
14 |
=================================================================== |
15 |
<?xml version='1.0' encoding="UTF-8"?> |
16 |
<!-- $Header: /var/cvsroot/gentoo/xml/htdocs/doc/es/articles/l-sed1.xml,v 1.1 2007/11/02 14:41:56 yoswink Exp $ --> |
17 |
<!DOCTYPE guide SYSTEM "/dtd/guide.dtd"> |
18 |
|
19 |
<guide link="/doc/es/articles/l-sed1.xml" disclaimer="articles" lang="es"> |
20 |
<title>Sed mediante ejemplos, Parte 1</title> |
21 |
|
22 |
<author title="Autor"> |
23 |
<mail link="drobbins@g.o">Daniel Robbins</mail> |
24 |
</author> |
25 |
<author title="Traductor"> |
26 |
<mail link="LinuxBlues@×××××××××.org">LinuxBlues</mail> |
27 |
</author> |
28 |
|
29 |
<abstract> |
30 |
En esta serie de artículos, Daniel Robbins mostrará cómo usar el poderoso |
31 |
(aunque muy a menudo olvidado) editor de flujo UNIX, sed. Sed es una |
32 |
herramienta ideal para editar archivos por lotes o para crear macros en el |
33 |
intérprete de comandos que modifiquen archivos existentes de forma muy |
34 |
poderosa. |
35 |
</abstract> |
36 |
|
37 |
<!-- The original version of this article was published on IBM developerWorks, |
38 |
and is property of Westtech Information Services. This document is an updated |
39 |
version of the original article, and contains various improvements made by the |
40 |
Gentoo Linux Documentation team --> |
41 |
|
42 |
<version>1.4</version> |
43 |
<date>2005-10-09</date> |
44 |
|
45 |
<chapter> |
46 |
<title>Dar a conocer el poderoso editor UNIX</title> |
47 |
<section> |
48 |
<title>Elegir un editor</title> |
49 |
<body> |
50 |
|
51 |
<p> |
52 |
En el mundo UNIX, disponemos de muchas opciones cuando necesitamos editar |
53 |
archivos. Pensando en ello -- vienen a la mente vi, emacs y jed, así como |
54 |
muchos otros. Todos nosotros tenemos nuestro editor favorito (así como nuestras |
55 |
combinaciones de teclas favoritas) que hemos llegado a conocer y ahora amamos. |
56 |
Con nuestro editor de confianza, estamos listos para manejar cualquier tarea de |
57 |
administración relacionada con UNIX o de programación con facilidad. |
58 |
</p> |
59 |
|
60 |
<p> |
61 |
Mientras que los editores interactivos son buenos, tienen algunas limitaciones. |
62 |
A pesar de que su naturaleza interactiva puede ser un punto fuerte, también |
63 |
puede ser una debilidad. Consideremos una situación en la que necesitemos hacer |
64 |
un tipo muy similar de cambios en un grupo de archivos. Podemos lanzar nuestro |
65 |
editor de textos favorito y realizar una labor mundana, tediosa y repetitiva, |
66 |
malgastando nuestro tiempo en muchas ediciones a mano. Pero hay una forma mejor |
67 |
de hacerlo |
68 |
</p> |
69 |
|
70 |
</body> |
71 |
</section> |
72 |
<section> |
73 |
<title>Introducción a sed</title> |
74 |
<body> |
75 |
|
76 |
<p> |
77 |
Sería bueno poder automatizar el proceso de editar archivos, de forma que |
78 |
podamos "procesar por lotes" la edición de archivos, e incluso crear macros con |
79 |
la habilidad de realizar cambios sofisticados a archivos existentes. |
80 |
Afortunadamente para nosotros y para este tipo de situaciones, hay un método |
81 |
mucho mejor -- y este método se denomina sed. |
82 |
</p> |
83 |
|
84 |
<p> |
85 |
sed es un ligero editor de flujo que está incluido en casi todos los |
86 |
sabores UNIX, Linux incluido. sed tiene muchas buenas características. La |
87 |
primera de ellas es que es de peso muy ligero, normalmente muy inferior al de |
88 |
nuestro lenguaje favorito de macros. En segundo lugar, dado que sed es un |
89 |
editor de flijo, puede editar los datos que recibe de stdin, como aquellos |
90 |
redireccionados. Por lo que no se necesita tener los datos a editar almacenados |
91 |
en un archivo del disco. Dado que los datos pueden redirigirse a sed, es muy |
92 |
fácil usar sed como parte de un largo y complejo redireccionamiento en un |
93 |
archivo por lotes de nuestro intérprete de comandos. Intentemos hacerlo con |
94 |
nuestro editor favorito. |
95 |
</p> |
96 |
|
97 |
</body> |
98 |
</section> |
99 |
<section> |
100 |
<title>sed GNU</title> |
101 |
<body> |
102 |
|
103 |
<p> |
104 |
Afortunadamente para nosotros, usuarios de Linux, una de las mejores versiones |
105 |
disponibles de sed es la versión de GNU, actualmente en su versión 3.02. Cada |
106 |
distribución de Linux posee el editor sed de GNU o, al menos, debería. El sed |
107 |
de GNU es muy conocido, no únicamente porque su código fuente sea de libre |
108 |
distribución, sino porque tiene muchas extensiones del estándar POSIX de sed |
109 |
que nos evitarán desperdiciar el tiempo. El sed de GNU tampoco sufre muchas de |
110 |
las limitaciones del sed anterior y propietario, como una longitud de línea |
111 |
limitada -- El sed de GNU puede manejar líneas de cualquier tamaño con |
112 |
facilidad. |
113 |
</p> |
114 |
|
115 |
</body> |
116 |
</section> |
117 |
<section> |
118 |
<title>El último sed de GNU</title> |
119 |
<body> |
120 |
|
121 |
<p> |
122 |
Mientras elaboraba este artículo, noté que varios aficionados de sed hacían |
123 |
referencia al sed de GNU 3.02a. A pesar de que no pude encontrarlo en |
124 |
<uri>ftp://ftp.gnu.org</uri> (ver los <uri link="#recursos">Recursos</uri> |
125 |
para encontrar estos enlaces), por lo que tuve que buscarlo en otra parte. Lo |
126 |
encontré en <uri>ftp://alpha.gnu.org</uri>, bajo <path>/pub/sed</path>. Lo |
127 |
descargué, compilé e instalé para observar, pasados unos minutos, que la última |
128 |
versión de sed es la 3.02.80 -- y puede encontrarse su código fuente justo al |
129 |
lado de las de 3.02a, en <uri>ftp://alpha.gnu.org</uri>. Después de tener el |
130 |
sed de GNU 3.02.80 instalado, ya estaba listo para continuar. |
131 |
</p> |
132 |
|
133 |
</body> |
134 |
</section> |
135 |
<section> |
136 |
<title>El sed correcto</title> |
137 |
<body> |
138 |
|
139 |
<p> |
140 |
En esta serie, utilizaré el sed de GNU versión 3.02.80. Algunos (aunque pocos) |
141 |
de los ejemplos más avanzados en mi serie de artículos acerca de sed no |
142 |
funcionarán con el sed de GNU 3.02 ó 3.02a. Si se está usando un sed que no sea |
143 |
el de GNU los resultados pueden variar. ¿Por qué no nos tomamos el tiempo |
144 |
necesario para instalar el sed 3.02.80 de GNU ahora? Después, no sólo estaremos |
145 |
preparados para el resto de los artículos acerca de sed, sino que estaremos |
146 |
usando, indiscutiblemente, el mejor sed que existe. |
147 |
</p> |
148 |
|
149 |
</body> |
150 |
</section> |
151 |
<section> |
152 |
<title>Ejemplos con sed</title> |
153 |
<body> |
154 |
|
155 |
<p> |
156 |
Sed trabaja realizando cualquier número de operaciones de edición especificadas |
157 |
por el usuario ("comandos") en los datos de entrada. Sed se basa en líneas, por |
158 |
lo que los comandos se realizan en cada línea, siguiendo un orden. Sed, escribe |
159 |
sus resultados en la salida estándar (stdout); por lo que no modifica ninguno |
160 |
de los archivos de entrada. |
161 |
</p> |
162 |
|
163 |
<p> |
164 |
Veamos algunos ejemplos. Los primeros van a ser un poco inútiles, debido a que |
165 |
pretendo mostrar con ellos cómo trabaja sed, en lugar de realizar cualquier |
166 |
tarea útil. De cualquier modo, si somos principiantes con sed, es muy |
167 |
importante entenderlos. He aquí nuestro primer ejemplo: |
168 |
</p> |
169 |
|
170 |
<pre caption="Ejemplo de uso de sed"> |
171 |
$ <i>sed -e 'd' /etc/services</i> |
172 |
</pre> |
173 |
|
174 |
<p> |
175 |
Si tecleamos este comando, no obtendremos absolutamente ningún mensaje. ¿Qué ha |
176 |
ocurrido? En este ejemplo, hemos llamado a sed con un comando de edición, |
177 |
<c>d</c>. Sed abrió el archivo <path>/etc/services</path>, leyó una línea en su |
178 |
memoria intermedia, realizó nuestro comando de edición ("borrar una línea") y |
179 |
después mostró su memoria intermedia de patrones (la cual estaba vacía). |
180 |
Después repitió estos pasos para cada línea sucesivamente. Con lo cual no se |
181 |
produjo ningún mensaje, dado que el comando <c>d</c> erradicó todas y cada una |
182 |
de las líneas en la memoria intermedia de patrones. |
183 |
</p> |
184 |
|
185 |
<p> |
186 |
Hay un par de cosas a considerar en este ejemplo. La primera, |
187 |
<path>/etc/services</path> no fue modificado en absoluto. Esto se debe a que |
188 |
sed únicamente lee del archivo que se le indica en la línea de comandos, |
189 |
usándolo como entrada -- ni siquiera intenta modificarlo. La segunda es que sed |
190 |
está orientado hacia líneas. El comando <c>d</c> no le dijo a sed que borrara |
191 |
todos los datos sin la más mínima precaución. En su lugar, sed leyó línea por |
192 |
línea /etc/services en su memoria intermedia interna, denominada memoria |
193 |
intermedia de patrones (pattern buffer). Cada vez que se leía una línea en la |
194 |
memoria intermedia de patrones, realizaba el comando <c>d</c> e imprimía los |
195 |
contenidos de la memoria intermedia de patrones (ninguno en este ejemplo). |
196 |
Después mostraré cómo usar rangos de direcciones para controlar las líneas a |
197 |
las que se aplica un comando -- aunque en ausencia de los mismos, un comando se |
198 |
aplica a todas las líneas. |
199 |
</p> |
200 |
|
201 |
<p> |
202 |
La tercera cosa a notar es el uso de comillas simples para introducir el |
203 |
comando <c>d</c>. Es una buena idea adquirir el hábito de usar comillas simples |
204 |
para introducir los comandos sed, para deshabilitar la expansión del intérprete |
205 |
de comandos. |
206 |
</p> |
207 |
|
208 |
</body> |
209 |
</section> |
210 |
<section> |
211 |
<title>Otro ejemplo de uso de sed</title> |
212 |
<body> |
213 |
|
214 |
<p> |
215 |
He aquí un ejemplo de cómo usar sed para eliminar la primera línea del archivo |
216 |
<path>/etc/services</path> de nuestro flujo de salida: |
217 |
</p> |
218 |
|
219 |
<pre caption="Otro ejemplo de uso de sed"> |
220 |
$ <i>sed -e '1d' /etc/services | more</i> |
221 |
</pre> |
222 |
|
223 |
<p> |
224 |
Como puede verse, este comando es muy similar a nuestro primer comando <c>d</c> |
225 |
exceptuando que se encuentra precedido por un <c>1</c>. Si al verlo hemos |
226 |
pensado que el <c>1</c> hacía alusión a la línea 1, estábamos en lo cierto. |
227 |
Mientras que en nuestro primer ejemplo usamos <c>d</c> por sí mismo, en este |
228 |
caso usamos el comando <c>d</c> precedido por una dirección lineal opcional. |
229 |
Usando direcciones, podemos decirle a sed que edite únicamente una línea o sólo |
230 |
unas líneas. |
231 |
</p> |
232 |
|
233 |
</body> |
234 |
</section> |
235 |
<section> |
236 |
<title>Rangos de direcciones</title> |
237 |
<body> |
238 |
|
239 |
<p> |
240 |
Ahora, veamos cómo especificar rangos de direcciones. En este ejemplo, sed |
241 |
borrará de la línea 1 a la 10 de la salida: |
242 |
</p> |
243 |
|
244 |
<pre caption="Especificar un rango de direcciones"> |
245 |
$ <i>sed -e '1,10d' /etc/services | more</i> |
246 |
</pre> |
247 |
|
248 |
<p> |
249 |
Cuando separamos dos direcciones por una coma, sed aplicará el siguiente |
250 |
comando al rango que empieza con la primera dirección y terminará con la |
251 |
segunda dirección. En este ejemplo, el comando <c>d</c> se ha aplicado desde la |
252 |
línea 1 hasta la línea 10, inclusive. El resto de líneas son ignoradas. |
253 |
</p> |
254 |
|
255 |
</body> |
256 |
</section> |
257 |
<section> |
258 |
<title>Direcciones con expresiones regulares</title> |
259 |
<body> |
260 |
|
261 |
<p> |
262 |
Ha llegado el momento de un ejemplo mucho más útil. Digamos que queríamos ver |
263 |
los contenidos del archivo <path>/etc/services</path>, pero no estamos |
264 |
interesados en ver ninguno de los comentarios incluidos. Como todos sabemos, se |
265 |
pueden añadir comentarios en nuestro archivo <path>/etc/services</path> |
266 |
comenzando la línea con un carácter '#'. Para evitar los comentarios, le |
267 |
indicamos a sed que elimine todas las líneas que comienzan con '#'. He aquí |
268 |
cómo hacerlo: |
269 |
</p> |
270 |
|
271 |
<pre caption="Eliminar las líneas que comienzan con #"> |
272 |
$ <i>sed -e '/^#/d' /etc/services | more</i> |
273 |
</pre> |
274 |
|
275 |
<p> |
276 |
Intentemos realizar este ejemplo y veamos lo que ocurre. Notaremos que sed |
277 |
realiza la labor solicitada con gran rapidez. Vamos a figurarnos qué es lo que |
278 |
ha ocurrido. |
279 |
</p> |
280 |
|
281 |
<p> |
282 |
Para comprender el comando '/^#/d', antes necesitamos diseccionarlo. Primero, |
283 |
eliminemos la 'd' -- estamos usando el mismo comando de borrado de líneas que |
284 |
hemos usado previamente. La nueva parte añadida es la '/^#/', que es un nuevo |
285 |
tipo de dirección mediante una expresión regular. Las direcciones con |
286 |
expresiones regulares se indican siempre entre barras. Especifican un patrón y |
287 |
el comando que está a continuación de una dirección con expresión regular |
288 |
únicamente se aplicará a una línea si encuentra dicho patrón en ella. |
289 |
</p> |
290 |
|
291 |
<p> |
292 |
Por lo que '/^#/' es una expresión regular. Pero, ¿qué es lo que hace? |
293 |
Obviamente, este sería un buen momento para repasar las expresiones regulares. |
294 |
</p> |
295 |
|
296 |
</body> |
297 |
</section> |
298 |
<section> |
299 |
<title>Repaso a las expresiones regulares</title> |
300 |
<body> |
301 |
|
302 |
<p> |
303 |
Podemos usar expresiones regulares para expresar patrones que podemos encontrar |
304 |
en el texto. Si hemos usado alguna vez el carácter '*' en un comando del |
305 |
intérprete de comandos, hemos usado algo muy similar, aunque no idéntico, a las |
306 |
expresiones regulares. Aquí tenemos los caracteres especiales que pueden usarse |
307 |
en las expresiones regulares: |
308 |
</p> |
309 |
|
310 |
<table> |
311 |
<tr> |
312 |
<th>Carácter</th> |
313 |
<th>Descripción</th> |
314 |
</tr> |
315 |
<tr> |
316 |
<ti>^</ti> |
317 |
<ti>Apunta al comienzo de la línea</ti> |
318 |
</tr> |
319 |
<tr> |
320 |
<ti>$</ti> |
321 |
<ti>Apunta al final de la línea</ti> |
322 |
</tr> |
323 |
<tr> |
324 |
<ti>.</ti> |
325 |
<ti>Apunta a un único carácter</ti> |
326 |
</tr> |
327 |
<tr> |
328 |
<ti>*</ti> |
329 |
<ti>Apunta a cero o más ocurrencias del carácter previo</ti> |
330 |
</tr> |
331 |
<tr> |
332 |
<ti>[ ]</ti> |
333 |
<ti>Apunta a todos los caracteres entre los corchetes</ti> |
334 |
</tr> |
335 |
</table> |
336 |
|
337 |
<p> |
338 |
Veamos algunos ejemplos con expresiones regulares para fascilitar las cosas. |
339 |
Todos estos ejemplos serán aceptados por sed como direcciones válidas que |
340 |
pueden aparecer a la izquierda de cualquier comando: |
341 |
</p> |
342 |
|
343 |
<table> |
344 |
<tr> |
345 |
<th>Expresión regular</th> |
346 |
<th>Descripción</th> |
347 |
</tr> |
348 |
<tr> |
349 |
<ti>/./</ti> |
350 |
<ti>Apuntará a cualquier línea que contenga al menos un carácter</ti> |
351 |
</tr> |
352 |
<tr> |
353 |
<ti>/../</ti> |
354 |
<ti>Apuntará a cualquier línea que contenga al menos dos caracteres</ti> |
355 |
</tr> |
356 |
<tr> |
357 |
<ti>/^#/</ti> |
358 |
<ti>Apuntará a cualquier línea que comience con un '#'</ti> |
359 |
</tr> |
360 |
<tr> |
361 |
<ti>/^$/</ti> |
362 |
<ti>Apuntará a cualquier línea en blanco</ti> |
363 |
</tr> |
364 |
<tr> |
365 |
<ti>/}^/</ti> |
366 |
<ti>Apuntará a toda línea que termine con un '}' (sin espacios)</ti> |
367 |
</tr> |
368 |
<tr> |
369 |
<ti>/} *^/</ti> |
370 |
<ti>Apuntará a toda línea que termine con un '}' con cero o más |
371 |
espacios</ti> |
372 |
</tr> |
373 |
<tr> |
374 |
<ti>/[abc]/</ti> |
375 |
<ti>Apuntará a toda línea que contenga una 'a', 'b', o 'c' minúscula</ti> |
376 |
</tr> |
377 |
<tr> |
378 |
<ti>/^[abc]/</ti> |
379 |
<ti>Apuntará a cualquier línea que empiece con 'a', 'b', o 'c'</ti> |
380 |
</tr> |
381 |
</table> |
382 |
|
383 |
<p> |
384 |
Recomiendo encarecidamente intentarlo con varios de estos ejemplos. Tomarse el |
385 |
tiempo necesario para familiarizarse con las expresiones regulares, e intentar |
386 |
usar algunas expresiones regulares de nuestra propia invención. Puede usarse |
387 |
una expreg de este modo: |
388 |
</p> |
389 |
|
390 |
<pre caption="Forma adecuada de usar expreg"> |
391 |
$ <i>sed -e '/expreg/d' /ruta/a/mi/archivo/de/pruebas | more</i> |
392 |
</pre> |
393 |
|
394 |
<p> |
395 |
Esto dará lugar a que sed borre cualquier línea coincidente. De todos modos, |
396 |
puede ser más sencillo familiarizarse con las expresiones regulares pidiéndole |
397 |
a sed que muestre las coincidencias con expreg y que borre las que no |
398 |
coincidan, en lugar de seguir el camino opuesto. Lo cual puede lograrse con el |
399 |
siguiente comando: |
400 |
</p> |
401 |
|
402 |
<pre caption="Imprimir las coincidencias expreg"> |
403 |
$ <i>sed -n -e '/expreg/p' /ruta/a/mi/archivo/de/pruebas | more</i> |
404 |
</pre> |
405 |
|
406 |
<p> |
407 |
Hay que tomar nota de la opción '-n', que indica a sed que no imprima el |
408 |
espacio en el patrón a menos que se le indique. También observamos que hemos |
409 |
sustituido el comando <c>d</c> con el comando <c>p</c>, que como se podrá |
410 |
pensar solicita a sed que muestre el espacio entre patrones. Por lo tanto, sólo |
411 |
se mostrarán las expresiones que coincidan. |
412 |
</p> |
413 |
|
414 |
</body> |
415 |
</section> |
416 |
<section> |
417 |
<title>Más direcciones</title> |
418 |
<body> |
419 |
|
420 |
<p> |
421 |
Hasta ahora, hemos echado un vistazo a direcciones lineales, direcciones en |
422 |
rangos lineales y direcciones expreg. Pero aún hay más posibilidades. Podemos |
423 |
especificar dos expresiones regulares separadas por una coma, y sed marcará |
424 |
todas las líneas que comiencen con la primera expresión regular seleccionada |
425 |
hasta la línea (incluida) que contenga la segunda expresión regular. Por |
426 |
ejemplo, el siguiente comando mostrará un bloque de texto que comience con una |
427 |
línea que contenga "PRINCIPIO", y termine con una línea que contenga "FIN": |
428 |
</p> |
429 |
|
430 |
<pre caption="Imprimir el bloque deseado de texto"> |
431 |
$ <i>sed -n -e '/PRINCIPIO/,/FIN/p' /mi/archivo/de/pruebas | more</i> |
432 |
</pre> |
433 |
|
434 |
<p> |
435 |
Si "PRINCIPIO" no se encuentra, no se imprimirá ningún dato. Y si se encuentra |
436 |
"PRINCIPIO" pero no se encuentra ninguna línea que contenga "FIN" a |
437 |
continuación, todas las líneas siguientes se imprimirán. Esto ocurre debido a |
438 |
la naturaleza basada en flujo de sed -- desconoce si "FIN" aparecerá o no. |
439 |
</p> |
440 |
|
441 |
</body> |
442 |
</section> |
443 |
<section> |
444 |
<title>Ejemplo con código fuente en C</title> |
445 |
<body> |
446 |
|
447 |
<p> |
448 |
Si únicamente se quiere imprimir la función main() en un archivo de código |
449 |
fuente en C, se podría teclear: |
450 |
</p> |
451 |
|
452 |
<pre caption="Imprimir la función main() en un archivo de código fuente en C"> |
453 |
$ <i>sed -n -e '/main[[:space:]]*(/,/^}/p' sourcefile.c | more</i> |
454 |
</pre> |
455 |
|
456 |
<p> |
457 |
Este comando tiene dos expresiones regulares, '/main[[:space:]]*(/' y '/^}/', y |
458 |
un comando , <c>p</c>. La primera expresión regular apuntará a la cadena "main" |
459 |
seguida de cualquier número de espacios o tabuladores, seguida además por un |
460 |
paréntesis abierto. Lo cual debería coincidir con el comienzo de nuestra |
461 |
declaración main() en ANSI C. |
462 |
</p> |
463 |
|
464 |
<p> |
465 |
En este caso de expresión regular, encontramos la clase de caracteres |
466 |
'[[:space:]]'. La cual es únicamente una palabra clave especial para sed que le |
467 |
indica a sed que apunte a cualquier espacio o TAB. De haberlo querido, en lugar |
468 |
de teclear '[[:space:]]', podríamos haber tecleado '[', después un espacio |
469 |
literalmente, a continuación Control-V, después un TAB literal y un ']' -- |
470 |
Control-V indica a bash que queremos introducir un TAB "real" en lugar de una |
471 |
expansión del comando. Es mucho más claro, especialmente en archivos de |
472 |
comandos usar la clase de comandos '[[:space:]]'. |
473 |
</p> |
474 |
|
475 |
<p> |
476 |
Bien, ahora la segunda expreg. '/^}/' apuntará a algún carácter '}' que |
477 |
aparezca al comienzo de una nueva línea. Si nuestro código se ha formateado |
478 |
correctamente, toparemos con ello con el final de nuestra función main(). Si no |
479 |
lo está, no lo hará -- cuestión de trabajar con la coincidencia de patrones. |
480 |
</p> |
481 |
|
482 |
<p> |
483 |
El comando <c>p</c> hace lo mismo que siempre, le dice a sed que imprima |
484 |
explícitamente la línea, dado que estamos en el modo silencioso '-n'. Si se |
485 |
intenta ejecutar el comando en una línea de código fuente en C, tratará de |
486 |
mostrar el bloque completo main() { }, incluyendo el "main ()" inicial y el '}' |
487 |
final. |
488 |
</p> |
489 |
|
490 |
</body> |
491 |
</section> |
492 |
<section> |
493 |
<title>La próxima vez</title> |
494 |
<body> |
495 |
|
496 |
<p> |
497 |
Ahora que hemos tratado los principios básicos, estamos listos para los |
498 |
siguientes dos artículos. Si necesitamos más material acerca de sed, hay que |
499 |
ser paciente -- se está elaborando. Mientras tanto, pueden consultarse los |
500 |
siguientes recursos acerca de sed y de las expresiones regulares. |
501 |
</p> |
502 |
|
503 |
</body> |
504 |
</section> |
505 |
</chapter> |
506 |
|
507 |
<chapter id="recursos"> |
508 |
<title>Recursos</title> |
509 |
<section> |
510 |
<title>Enlaces útiles</title> |
511 |
<body> |
512 |
|
513 |
<ul> |
514 |
<li> |
515 |
Leer los otros artículos acerca de sed de Daniel en developerWorks: "Sed |
516 |
mediante ejemplos, <uri link="/doc/es/articles/l-sed2.xml">Parte 2</uri> y |
517 |
<uri link="/doc/es/articles/l-sed3.xml">Parte 3</uri>. |
518 |
</li> |
519 |
<li> |
520 |
Comprobar la excelente <uri |
521 |
link="http://www.student.northpark.edu/pemente/sed/sedfaq.html">sed FAQ</uri> |
522 |
de Eric Pement. |
523 |
</li> |
524 |
<li> |
525 |
Se puede encontrar el código fuente de sed 3.02 en |
526 |
<uri>ftp://ftp.gnu.org/pub/gnu/sed</uri>. |
527 |
</li> |
528 |
<li> |
529 |
Se puede encontrar el nuevo sed 3.02.80 en <uri>ftp://alpha.gnu.org</uri>. |
530 |
</li> |
531 |
<li> |
532 |
Eric Pement tiene también una lista muy práctica de <uri |
533 |
link="http://www.student.northpark.edu/pemente/sed/sed1line.txt">sed one-liners</uri> |
534 |
que cualquier aspirante a gurú sed debería consultar. |
535 |
</li> |
536 |
<li> |
537 |
Si nos gustan los libros tradicionales, <uri |
538 |
link="http://www.oreilly.com/catalog/sed2/">O'Reilly's sed & awk, 2nd |
539 |
Edition</uri> sería una gran elección. |
540 |
</li> |
541 |
<!-- FIXME BOTH DEAD and not possible to find other locations, sorry |
542 |
<li> |
543 |
Maybe you'd like to read <uri |
544 |
link="http://www.softlab.ntua.gr/unix/docs/sed.txt">7th edition UNIX's sed |
545 |
man page</uri> (circa 1978!). |
546 |
</li> |
547 |
<li> |
548 |
Take Felix von Leitner's short <uri |
549 |
link="http://www.math.fu-berlin.de/~leitner/sed/tutorial.html">sed |
550 |
tutorial</uri>. |
551 |
</li> |
552 |
--> |
553 |
<li> |
554 |
Leer el artículo de David Mertz acerca del <uri |
555 |
link="http://www-106.ibm.com/developerworks/linux/library/l-python5.html"> |
556 |
Procesamiento de texto bajo Python</uri> (en inglés) en developerWorks. |
557 |
</li> |
558 |
<!-- Dead link |
559 |
<li> |
560 |
Brush up on <uri link="http://vision.eng.shu.ac.uk/C++/misc/regexp/">using |
561 |
regular expressions</uri> to find and modify patterns in text in this free, |
562 |
dW-exclusive tutorial. |
563 |
</li> |
564 |
--> |
565 |
<li> |
566 |
Ver el <uri |
567 |
link="http://www.python.org/doc/howto/regex/regex.html">Regular Expression |
568 |
HOWTO</uri> (en inglés) de <uri link="http://python.org">Python.org</uri>. |
569 |
</li> |
570 |
<li> |
571 |
Tener en cuenta el <uri |
572 |
link="http://www.uky.edu/ArtsSciences/Classics/regex.html">Regular |
573 |
Expression Overview</uri> (en inglés) de la Universidad de Kentucky. |
574 |
</li> |
575 |
</ul> |
576 |
|
577 |
</body> |
578 |
</section> |
579 |
</chapter> |
580 |
|
581 |
</guide> |
582 |
|
583 |
|
584 |
|
585 |
1.1 xml/htdocs/doc/es/articles/l-sed2.xml |
586 |
|
587 |
file : http://sources.gentoo.org/viewcvs.py/gentoo/xml/htdocs/doc/es/articles/l-sed2.xml?rev=1.1&view=markup |
588 |
plain: http://sources.gentoo.org/viewcvs.py/gentoo/xml/htdocs/doc/es/articles/l-sed2.xml?rev=1.1&content-type=text/plain |
589 |
|
590 |
Index: l-sed2.xml |
591 |
=================================================================== |
592 |
<?xml version='1.0' encoding="UTF-8"?> |
593 |
<!-- $Header: /var/cvsroot/gentoo/xml/htdocs/doc/es/articles/l-sed2.xml,v 1.1 2007/11/02 14:41:56 yoswink Exp $ --> |
594 |
<!DOCTYPE guide SYSTEM "/dtd/guide.dtd"> |
595 |
|
596 |
<guide link="/doc/es/articles/l-sed2.xml" disclaimer="articles" lang="es"> |
597 |
<title>Sed mediante ejemplos, Parte 2</title> |
598 |
|
599 |
<author title="Autor"> |
600 |
<mail link="drobbins@g.o">Daniel Robbins</mail> |
601 |
</author> |
602 |
<author title="Traductor"> |
603 |
<mail link="LinuxBlues@×××××××××.org">LinuxBlues</mail> |
604 |
</author> |
605 |
|
606 |
|
607 |
<abstract> |
608 |
Sed es un poderoso y compacto editor de flujos de texto. En este artículo, el |
609 |
segundo de la serie, Daniel muestra cómo realizar sustituciones de cadenas; |
610 |
crear archivos de comandos más amplios y usar los comandos de sed para añadir, |
611 |
insertar y modificar una línea. |
612 |
</abstract> |
613 |
|
614 |
<!-- The original version of this article was published on IBM developerWorks, |
615 |
and is property of Westtech Information Services. This document is an updated |
616 |
version of the original article, and contains various improvements made by the |
617 |
Gentoo Linux Documentation team --> |
618 |
|
619 |
<version>1.2</version> |
620 |
<date>2005-10-09</date> |
621 |
|
622 |
<chapter> |
623 |
<title>Cómo aprovechar más el editor UNIX</title> |
624 |
<section> |
625 |
<title>¡Sustitución!</title> |
626 |
<body> |
627 |
|
628 |
<p> |
629 |
Veamos uno de los comandos más útiles de sed, el de sustitución. Usándolo, |
630 |
podemos reemplazar una cadena en concreto o la expresión regular coincidente |
631 |
con otra cadena. He aquí un ejemplo del uso más básico de este comando: |
632 |
</p> |
633 |
|
634 |
<pre caption="El uso más básico del comando de sustitución"> |
635 |
$ <i>sed -e 's/foo/bar/' miarchivo.txt</i> |
636 |
</pre> |
637 |
|
638 |
<p> |
639 |
El comando anterior sacará los contenidos de miarchivo.txt a stdout, con la |
640 |
primera aparición de 'foo' (si es que hay alguna) reemplazada en cada línea por |
641 |
la cadena 'bar'. Por favor, hay que tener en cuenta que he dicho la primera |
642 |
aparición en cada línea, a pesar de que esto no es lo que se desea normalmente. |
643 |
Cuando quiero realizar la sustitución de una cadena, normalmente la quiero |
644 |
realizar globalmente. Dicho con otras palabras, quiero reemplazar la expresión |
645 |
todas las veces que se muestra, como sigue: |
646 |
</p> |
647 |
|
648 |
<pre caption="Reemplazar todas las coincidencias en cada línea"> |
649 |
$ <i>sed -e 's/foo/bar/g' miarchivo.txt</i> |
650 |
</pre> |
651 |
|
652 |
<p> |
653 |
La opción adicional 'g' después de la última barra le indica a sed que debe |
654 |
realizar el reemplazo de forma global. |
655 |
</p> |
656 |
|
657 |
<p> |
658 |
He aquí algunas otras cosas que se deben saber acerca del comando de |
659 |
sustitución <c>s///</c>. La primera es que se trata de un comando y de un |
660 |
comando únicamente; no hay ninguna dirección mostrada en los ejemplos |
661 |
anteriores. Lo cual significa que el comando <c>s///</c> puede usarse con |
662 |
directivas acerca de las direcciones a las cuales se aplicará, como se muestra: |
663 |
</p> |
664 |
|
665 |
<pre caption="Especificar las líneas a las que se aplicará el comando"> |
666 |
$ <i>sed -e '1,10s/enchantment/entrapment/g' miarchivo2.txt</i> |
667 |
</pre> |
668 |
|
669 |
<p> |
670 |
El ejemplo anterior causará que todas las veces que aparezca 'enchantment' se |
671 |
reemplace por 'entrapment', pero sólo hasta la línea 10, inclusive. |
672 |
</p> |
673 |
|
674 |
<pre caption="Especificar más opciones"> |
675 |
$ <i>sed -e '/^$/,/^FIN/s/colinas/montañas/g' miarchivo3.txt</i> |
676 |
</pre> |
677 |
|
678 |
<p> |
679 |
Este ejemplo cambiará 'colinas' por 'montañas', pero únicamente en los bloques |
680 |
de texto que comiencen con una línea en blanco, y que terminen con una línea |
681 |
que comience con los tres caracteres 'FIN', inclusive. |
682 |
</p> |
683 |
|
684 |
<p> |
685 |
Otra de las buenas cosas acerca del comando <c>s///</c> es que tenemos muchas |
686 |
opciones cuando usamos estos <c>/</c> separadores. Si estamos realizando la |
687 |
sustitución de una cadena y la expresión regular o el reemplazo tiene muchas |
688 |
barras, podemos cambiar el separador especificando un carácter distinto después |
689 |
de la 's'. Por ejemplo, lo siguiente cambiará el contenido cambiando |
690 |
<path>/usr/local</path> por <path>/usr</path>: |
691 |
</p> |
692 |
|
693 |
<pre caption="Reemplazar todas las apariciones de una cadena con otra"> |
694 |
$ <i>sed -e 's:/usr/local:/usr:g' milista.txt</i> |
695 |
</pre> |
696 |
|
697 |
<note> |
698 |
En este ejemplo, estamos usando los dos puntos como separador. Si alguna vez |
699 |
necesitamos especificar el carácter separador en nuestra expresión regular hay |
700 |
que ponerle antes una barra invertida. |
701 |
</note> |
702 |
|
703 |
</body> |
704 |
</section> |
705 |
<section> |
706 |
<title>La caótica confusión con las expreg</title> |
707 |
<body> |
708 |
|
709 |
<p> |
710 |
Hasta ahora, únicamente hemos realizado una simple sustitución de cadenas. |
711 |
Aunque esto puede ser muy útil, podemos también buscar expresiones regulares. |
712 |
Por ejemplo, el siguiente comando sed encontrará una frase que comience con |
713 |
'<' y termine con '>', y que contenga cualquier número de caracteres |
714 |
entremedias. Esta frase se borrará (será reemplazada por una cadena sin |
715 |
contenido): |
716 |
</p> |
717 |
|
718 |
<pre caption="Borrar la frase especificada"> |
719 |
$ <i>sed -e 's/<.*>//g' miarchivo.html</i> |
720 |
</pre> |
721 |
|
722 |
<p> |
723 |
Un buen comienzo con un archivo de comandos sed sería eliminar todas las |
724 |
etiquetas HTML de un archivo, pero no funcionará de forma correcta, debido a |
725 |
algo que hace especiales a las expresiones regulares. ¿Cuál es la razón? Cuando |
726 |
sed intenta encontrar la expresión regular en una línea, encuentra la |
727 |
coincidencia más larga en la línea. Esto no era ningún problema en mi anterior |
728 |
artículo acerca de sed, dado que estaba usando los comandos <c>d</c> y |
729 |
<c>p</c>, que borrarían la línea completa de todas formas. Pero cuando usamos |
730 |
el comando <c>s///</c>, es muy diferente, dado que todo aquello con lo que |
731 |
coincida la expresión regular será reemplazado con la cadena de sustitución, o |
732 |
en este caso, eliminado. Lo cual significa que, en el ejemplo anterior, |
733 |
convertirá la siguiente línea: |
734 |
</p> |
735 |
|
736 |
<pre caption="ejemplo de código HTML"> |
737 |
<b>Esto</b> es lo que <b>I</b> quería decir. |
738 |
</pre> |
739 |
|
740 |
<p> |
741 |
en esta otra: |
742 |
</p> |
743 |
|
744 |
<pre caption="Efecto indeseado"> |
745 |
quería decir. |
746 |
</pre> |
747 |
|
748 |
<p> |
749 |
en lugar de hacer esto otro, que era lo que pretendíamos: |
750 |
</p> |
751 |
|
752 |
<pre caption="Efecto deseado"> |
753 |
Esto es lo que quería decir. |
754 |
</pre> |
755 |
|
756 |
<p> |
757 |
Afortunadamente, hay una forma sencilla de resolverlo. En lugar de teclear una |
758 |
expresión regular que indique "un carácter '<' seguido de cualquier número |
759 |
de caracteres y que termine con un carácter '>'". Lo cual tendrá el efecto |
760 |
de apuntar a la menor coincidencia posible, en lugar de a la mayor de ellas. El |
761 |
nuevo comando sería similar a este: |
762 |
</p> |
763 |
|
764 |
<pre caption=""> |
765 |
$ <i>sed -e 's/<[^>]*>//g' miarchivo.html</i> |
766 |
</pre> |
767 |
|
768 |
<p> |
769 |
En el ejemplo anterior, el '[^>]' especifica un "carácter que no sea '>'" |
770 |
y el '*' después del mismo completa la expresión para significar "cero o más |
771 |
caracteres que no sean '>'". Recomiendo probar este comando con algunos |
772 |
archivos HTML de ejemplo, encauzarlos con more y comprobar los resultados. |
773 |
</p> |
774 |
|
775 |
</body> |
776 |
</section> |
777 |
<section> |
778 |
<title>Coincidencia con más caracteres</title> |
779 |
<body> |
780 |
|
781 |
<p> |
782 |
La sintaxis de expresiones regulares '[ ]' tiene más opciones adicionales. Para |
783 |
especificar un rango de caracteres se puede usar '-', siempre y cuando no esté |
784 |
ni en la primera ni en la última posición, como se muestra a continuación: |
785 |
</p> |
786 |
|
787 |
<pre caption="Especificar un rango de caracteres"> |
788 |
'[a-x]*' |
789 |
</pre> |
790 |
|
791 |
<p> |
792 |
Apuntará a cero o más caracteres, siempre que cada uno de ellos sea una 'a', |
793 |
'b','c'...'v','w','x'. Además, la clase de caracteres '[:space:]' está |
794 |
disponible para coincidir con espacios en blanco. He aquí una lista bastante |
795 |
completa de clases de caracteres: |
796 |
</p> |
797 |
|
798 |
|
799 |
<table> |
800 |
<tr> |
801 |
<th>Clase de carácter</th> |
802 |
<th>Descripción</th> |
803 |
</tr> |
804 |
<tr> |
805 |
<ti>[:alnum:]</ti> |
806 |
<ti>Alfanumérico [a-z A-Z 0-9]</ti> |
807 |
</tr> |
808 |
<tr> |
809 |
<ti>[:alpha:]</ti> |
810 |
<ti>Alfabético [a-z A-Z]</ti> |
811 |
</tr> |
812 |
<tr> |
813 |
<ti>[:blank:]</ti> |
814 |
<ti>Espacios o tabuladores</ti> |
815 |
</tr> |
816 |
<tr> |
817 |
<ti>[:cntrl:]</ti> |
818 |
<ti>Cualquier carácter de control</ti> |
819 |
</tr> |
820 |
<tr> |
821 |
<ti>[:digit:]</ti> |
822 |
<ti>Dígitos numéricos [0-9]</ti> |
823 |
</tr> |
824 |
<tr> |
825 |
<ti>[:graph:]</ti> |
826 |
<ti>Cualquier carácter visible (no espacios en blanco)</ti> |
827 |
</tr> |
828 |
<tr> |
829 |
<ti>[:lower:]</ti> |
830 |
<ti>Minúsculas [a-z]</ti> |
831 |
</tr> |
832 |
<tr> |
833 |
<ti>[:print:]</ti> |
834 |
<ti>Caracteres que no sean de control</ti> |
835 |
</tr> |
836 |
<tr> |
837 |
<ti>[:punct:]</ti> |
838 |
<ti>Caracteres de puntuación</ti> |
839 |
</tr> |
840 |
<tr> |
841 |
<ti>[:space:]</ti> |
842 |
<ti>Espacio en blanco</ti> |
843 |
</tr> |
844 |
<tr> |
845 |
<ti>[:upper:]</ti> |
846 |
<ti>Mayúsculas [A-Z]</ti> |
847 |
</tr> |
848 |
<tr> |
849 |
<ti>[:xdigit:]</ti> |
850 |
<ti>Dígitos hexadecimales [0-9 a-f A-F]</ti> |
851 |
</tr> |
852 |
</table> |
853 |
|
854 |
<p> |
855 |
Es una gran ventaja usar clases de caracteres siempre que sea posible, dado que |
856 |
se adaptan mejor a las locales no inglesas (incluyendo caracteres con acentos |
857 |
siempre que sea necesario, etc.). |
858 |
</p> |
859 |
|
860 |
</body> |
861 |
</section> |
862 |
<section> |
863 |
<title>Asuntos de sustitución avanzada</title> |
864 |
<body> |
865 |
|
866 |
<p> |
867 |
Nos hemos detenido con la realización de simples e incluso complejas |
868 |
sustituciones directas, pero sed puede hacer mucho más. Podemos referirnos a |
869 |
partes o a cadenas enteras con las que coincida la expresión regular y usar |
870 |
estas partes para construir la cadena de reemplazo. Como ejemplo, digamos que |
871 |
estamos respondiendo a un mensaje. El siguiente ejemplo pondrá el prefijo "Rafa |
872 |
dijo: " a cada frase: |
873 |
</p> |
874 |
|
875 |
<pre caption="Añadir un prefijo a cada frase con cierta cadena"> |
876 |
$ <i>sed -e 's/.*/Rafa dijo: &/' msjorig.txt</i> |
877 |
</pre> |
878 |
|
879 |
<p> |
880 |
La salida será similar a esta: |
881 |
</p> |
882 |
|
883 |
<pre caption="Salida del anterior comando"> |
884 |
Rafa dijo: Hola Jaime, |
885 |
Rafa dijo: |
886 |
Rafa dijo: ¡Seguro que me gusta este material acerca de sed! |
887 |
Rafa dijo: |
888 |
</pre> |
889 |
|
890 |
<p> |
891 |
En este ejemplo, usamos el carácter '&' en la cadena de reemplazo, que le |
892 |
indica a sed que inserte la expresión regular completa con la que coincida. Por |
893 |
lo que todo lo que coincidió con '.*' (el mayor grupo de cero o más caracteres |
894 |
en la línea, o la línea completa) puede ser introducido en la cadena de |
895 |
reemplazo, incluso en múltiples ocasiones. Esto está muy bien, pero sed es |
896 |
mucho más poderoso aún. |
897 |
</p> |
898 |
|
899 |
</body> |
900 |
</section> |
901 |
<section> |
902 |
<title>Aquellos maravillosos paréntesis con barras invertidas</title> |
903 |
<body> |
904 |
|
905 |
<p> |
906 |
Aún mejor que con '&', el comando <c>s///</c> nos permite definir regiones |
907 |
en nuestra expresión regular, y podemos referirnos a estas regiones específicas |
908 |
en nuestra cadena de reemplazo. Como ejemplo, digamos que tenemos un archivo |
909 |
que contiene el siguiente texto: |
910 |
</p> |
911 |
|
912 |
<pre caption="Cita del texto"> |
913 |
foo bar oni |
914 |
eeny meeny miny |
915 |
larry curly moe |
916 |
jimmy the weasel |
917 |
</pre> |
918 |
|
919 |
<p> |
920 |
Ahora, digamos que queremos escribir un archivo de comandos sed que reemplace |
921 |
"eeny meeny miny" con "Victor eeny-meeny Von miny", etc. Para hacerlo, primero |
922 |
deberíamos escribir una expresión regular con la que coincidan las tres |
923 |
cadenas, separadas por espacios: |
924 |
</p> |
925 |
|
926 |
<pre caption="Coincidir con la expresión regular"> |
927 |
'.* .* .*' |
928 |
</pre> |
929 |
|
930 |
<p> |
931 |
Aquí está. Ahora, definiremos regiones insertando paréntesis con barras |
932 |
invertidas alrededor de cada región de nuestro interés: |
933 |
</p> |
934 |
|
935 |
<pre caption="Definición de regiones"> |
936 |
'\(.*\) \(.*\) \(.*\)' |
937 |
</pre> |
938 |
|
939 |
<p> |
940 |
Esta expresión regular funcionará exactamente igual que la anterior, excepto |
941 |
porque definirá tres regiones lógicas a las que podremos referirnos en nuestra |
942 |
cadena de reemplazo. He aquí el archivo de comandos final: |
943 |
</p> |
944 |
|
945 |
<pre caption="Archivo de comandos final"> |
946 |
$ <i>sed -e 's/\(.*\) \(.*\) \(.*\)/Victor \1-\2 Von \3/' miarchivo.txt</i> |
947 |
</pre> |
948 |
|
949 |
<p> |
950 |
Como puede verse, nos referimos a cada región delimitada por un paréntesis |
951 |
tecleando '\x', donde x es el número de región, comenzando por uno. El |
952 |
resultado será el siguiente: |
953 |
</p> |
954 |
|
955 |
<pre caption="Resultado del anterior comando"> |
956 |
Victor foo-bar Von oni |
957 |
Victor eeny-meeny Von miny |
958 |
Victor larry-curly Von moe |
959 |
Victor jimmy-the Von weasel |
960 |
</pre> |
961 |
|
962 |
<p> |
963 |
A medida que uno se familiariza con sed, puede realizarse un procesamiento de |
964 |
textos realmente poderoso con un mínimo de esfuerzo. Pensemos ahora en cómo |
965 |
habríamos afrontado este mismo problema con nuestro lenguaje para crear |
966 |
archivos de comandos favorito -- ¿habríamos sido capaces de encontrar la |
967 |
solución con una sola línea? |
968 |
</p> |
969 |
|
970 |
</body> |
971 |
</section> |
972 |
<section> |
973 |
<title>Combinarlo todo</title> |
974 |
<body> |
975 |
|
976 |
<p> |
977 |
A medida que creamos archivos de comandos con sed más complejos, necesitaremos |
978 |
la capacidad para introducir más de un comando. Hay varias formas de lograrlo. |
979 |
Primero podemos usar puntos y comas entre los comandos. Por ejemplo, en esta |
980 |
serie de comandos se emplea el comando '=', que le indica a sed que muestre el |
981 |
número de línea, así como el comando <c>p</c>, que le indica a sed que muestre |
982 |
la línea (dado que estamos en el modo '-n'): |
983 |
</p> |
984 |
|
985 |
<pre caption="Primer método, puntos y comas"> |
986 |
$ <i>sed -n -e '=;p' myfile.txt</i> |
987 |
</pre> |
988 |
|
989 |
<p> |
990 |
Cada vez que se indiquen dos o más comandos, se ejecutará cada comando (en |
991 |
orden) para cada línea del archivo. En el ejemplo anterior, primero se aplica |
992 |
el comando '=' a la línea 1, y después se le aplica el comando <c>p</c>. |
993 |
Entonces sed procede con la línea 2 y repite el proceso. Mientras que los |
994 |
puntos y comas son muy útiles, hay ciertas situaciones en las que no |
995 |
funcionará. Otra alternativa sería usar dos opciones -e para especificar dos |
996 |
comandos separados: |
997 |
</p> |
998 |
|
999 |
<pre caption="Segundo método, múltiples -e"> |
1000 |
$ <i>sed -n -e '=' -e 'p' miarchivo.txt</i> |
1001 |
</pre> |
1002 |
|
1003 |
<p> |
1004 |
De todas formas, cuando nos adentremos en comandos más complejos para añadir e |
1005 |
insertar texto, no será suficiente con múltiples opciones '-e'. Para archivos |
1006 |
de comandos complejos con varias líneas, el método más adecuado es poner todos |
1007 |
esos comandos en un archivo diferente. Después haremos referencia a este |
1008 |
archivo de comandos con la opción -f: |
1009 |
</p> |
1010 |
|
1011 |
<pre caption="Tercer método, archivo externo con comandos"> |
1012 |
$ <i>sed -n -f miscomandos.sed miarchivo.txt</i> |
1013 |
</pre> |
1014 |
|
1015 |
<p> |
1016 |
Este método, aunque parezca menos conveniente, siempre funcionará. |
1017 |
|
1018 |
</p> |
1019 |
|
1020 |
</body> |
1021 |
</section> |
1022 |
<section> |
1023 |
<title>Múltiples comandos en una sola dirección</title> |
1024 |
<body> |
1025 |
|
1026 |
<p> |
1027 |
A veces, podemos querer especificar múltiples comandos que se apliquen en una |
1028 |
sola dirección. Lo cual es realmente útil cuando se realizan montones de |
1029 |
<c>s///</c> para modificar palabras o la sintaxis de un archivo. Para realizar |
1030 |
múltiples comandos en una sola dirección, introducimos nuestros comandos sed en |
1031 |
un archivo y usamos los caracteres de llaves '{ }' para agruparlos, como sigue: |
1032 |
</p> |
1033 |
|
1034 |
<pre caption="Introducción de múltiples comandos por dirección"> |
1035 |
1,20{ |
1036 |
s/[Ll]inux/GNU\/Linux/g |
1037 |
s/samba/Samba/g |
1038 |
s/posix/POSIX/g |
1039 |
} |
1040 |
</pre> |
1041 |
|
1042 |
<p> |
1043 |
El ejemplo anterior aplicará tres comandos de sustitución desde la línea 1 a la |
1044 |
20, inclusive. Se pueden expresar también direcciones con expresiones regulares |
1045 |
o una combinación de ambas: |
1046 |
</p> |
1047 |
|
1048 |
<pre caption="Combinación de ambos métodos"> |
1049 |
1,/^END/{ |
1050 |
s/[Ll]inux/GNU\/Linux/g |
1051 |
s/samba/Samba/g |
1052 |
s/posix/POSIX/g |
1053 |
p |
1054 |
} |
1055 |
</pre> |
1056 |
|
1057 |
<p> |
1058 |
Este ejemplo aplicará todos los comandos entre '{ }' a las líneas que se |
1059 |
encuentren entre la primera y aquella que comience con las letras "END", o |
1060 |
hasta el final del archivo, si no se encuentra "END" antes. |
1061 |
</p> |
1062 |
|
1063 |
</body> |
1064 |
</section> |
1065 |
<section> |
1066 |
<title>Añadir, insertar y cambiar de línea</title> |
1067 |
<body> |
1068 |
|
1069 |
<p> |
1070 |
Ahora que estamos escribiendo archivos de comandos sed en archivos separados, |
1071 |
podemos aprovechar los comandos para añadir, insertar y cambiar de línea. Estos |
1072 |
comandos insertarán una línea después de la línea actual, insertarán una línea |
1073 |
antes de la línea actual o reemplazarán a la línea actual en el espacio de |
1074 |
patrones. Pueden usarse para insertar múltiples líneas en su salida. El comando |
1075 |
para insertar líneas se usa como sigue: |
1076 |
</p> |
1077 |
|
1078 |
<pre caption="Usar el comando para insertar líneas"> |
1079 |
i\ |
1080 |
Esta línea se insertará antes de cada línea |
1081 |
</pre> |
1082 |
|
1083 |
<p> |
1084 |
Si no se especifica ninguna dirección en la que aplicar este comando, se |
1085 |
aplicará a cada línea y producirá un resultado como el siguiente: |
1086 |
</p> |
1087 |
|
1088 |
<pre caption="Resultados del anterior comando"> |
1089 |
Esta línea se insertará antes de cada línea |
1090 |
línea 1 aquí |
1091 |
Esta línea se insertará antes de cada línea |
1092 |
línea 2 aquí |
1093 |
Esta línea se insertará antes de cada línea |
1094 |
línea 3 aquí |
1095 |
Esta línea se insertará antes de cada línea |
1096 |
línea 4 aquí |
1097 |
</pre> |
1098 |
|
1099 |
<p> |
1100 |
Si se quieren insertar varias líneas antes de la actual, se pueden añadir |
1101 |
agregando una barra invertida a la línea anterior, como se muestra: |
1102 |
</p> |
1103 |
|
1104 |
<pre caption="Insertar varias líneas antes de la actual"> |
1105 |
i\ |
1106 |
inserta esta línea\ |
1107 |
y esta otra\ |
1108 |
y esta otra\ |
1109 |
y, ¡ah!, esta también. |
1110 |
</pre> |
1111 |
|
1112 |
<p> |
1113 |
El comando para añadir funciona de forma similar, pero insertará una línea o |
1114 |
líneas después de la actual en el espacio de patrones. Se usa como sigue: |
1115 |
</p> |
1116 |
|
1117 |
<pre caption="Añadir líneas después de la actual"> |
1118 |
a\ |
1119 |
Añade esta línea después de cada línea. ¡Gracias! :) |
1120 |
</pre> |
1121 |
|
1122 |
<p> |
1123 |
Por otra parte, el comando para cambiar de línea reemplazará la línea actual |
1124 |
en el espacio de patrones, y se usa como se indica: |
1125 |
</p> |
1126 |
|
1127 |
<p> |
1128 |
Dado que el comando para añadir, insertar y cambiar de línea necesitan ser |
1129 |
indicados en varias líneas, es necesario teclearlos en archivos de comandos de |
1130 |
texto e indicar a sed que los ejecute con la opción '-f'. Usar los otros |
1131 |
métodos de sed para introducir comandos resultará problemático. |
1132 |
</p> |
1133 |
|
1134 |
</body> |
1135 |
</section> |
1136 |
<section> |
1137 |
<title>La próxima vez</title> |
1138 |
<body> |
1139 |
|
1140 |
<p> |
1141 |
La próxima vez, en el último artículo acerca de sed en esta serie, mostraré |
1142 |
muchos ejemplos excelentes de uso en el mundo real para muchos tipos diferentes |
1143 |
de tareas. No solamente mostraré lo que los archivos de comandos hacen sino |
1144 |
porqué lo hacen. Después de consultarlo, dispondremos de muchas ideas |
1145 |
adicionales excelentes acerca de cómo usar sed en nuestros proyectos. ¡Nos |
1146 |
vemos ! |
1147 |
</p> |
1148 |
|
1149 |
</body> |
1150 |
</section> |
1151 |
</chapter> |
1152 |
|
1153 |
<chapter> |
1154 |
<title>Recursos</title> |
1155 |
<section> |
1156 |
<title>Enlaces útiles</title> |
1157 |
<body> |
1158 |
|
1159 |
<ul> |
1160 |
<li> |
1161 |
Leer los otros artículos acerca de sed de Daniel en developerWorks: "Sed |
1162 |
mediante ejemplos, <uri link="/doc/es/articles/l-sed1.xml">Parte 1</uri> y |
1163 |
<uri link="/doc/es/articles/l-sed3.xml">Parte 3</uri>. |
1164 |
</li> |
1165 |
<li> |
1166 |
Comprobar la excelente <uri |
1167 |
link="http://www.student.northpark.edu/pemente/sed/sedfaq.html">se FAQ</uri> |
1168 |
de Eric Pement. |
1169 |
</li> |
1170 |
<li> |
1171 |
Se puede encontrar el código fuente de sed 3.02 en |
1172 |
<uri>ftp://ftp.gnu.org/pub/gnu/sed</uri>. |
1173 |
</li> |
1174 |
<li> |
1175 |
Se puede encontrar el nuevo sed 3.02.80 en <uri>ftp://alpha.gnu.org</uri>. |
1176 |
</li> |
1177 |
<li> |
1178 |
Eric Pement tiene también una lista muy práctica de <uri |
1179 |
link="http://www.student.northpark.edu/pemente/sed/sed1line.txt">sed one-liners</uri> |
1180 |
que cualquier aspirante a gurú sed debería consultar. |
1181 |
</li> |
1182 |
<li> |
1183 |
Si nos gustan los libros tradicionales, <uri |
1184 |
link="http://www.oreilly.com/catalog/sed2/">O'Reilly's sed & awk, 2nd |
1185 |
Edition</uri> sería una gran elección. |
1186 |
</li> |
1187 |
<!-- FIXME BOTH DEAD and no other locations, sorry |
1188 |
<li> |
1189 |
Maybe you'd like to read <uri |
1190 |
link="http://www.softlab.ntua.gr/unix/docs/sed.txt">7th edition UNIX's sed |
1191 |
man page</uri> (circa 1978!). |
1192 |
</li> |
1193 |
<li> |
1194 |
Take Felix von Leitner's short <uri |
1195 |
link="http://www.math.fu-berlin.de/~leitner/sed/tutorial.html">sed |
1196 |
tutorial</uri>. |
1197 |
</li> |
1198 |
<li> |
1199 |
Brush up on <uri link="http://vision.eng.shu.ac.uk/C++/misc/regexp/">using |
1200 |
regular expressions</uri> to find and modify patterns in text in this free, |
1201 |
dW-exclusive tutorial. |
1202 |
</li> |
1203 |
--> |
1204 |
</ul> |
1205 |
|
1206 |
</body> |
1207 |
</section> |
1208 |
</chapter> |
1209 |
|
1210 |
</guide> |
1211 |
|
1212 |
|
1213 |
|
1214 |
1.1 xml/htdocs/doc/es/articles/l-sed3.xml |
1215 |
|
1216 |
file : http://sources.gentoo.org/viewcvs.py/gentoo/xml/htdocs/doc/es/articles/l-sed3.xml?rev=1.1&view=markup |
1217 |
plain: http://sources.gentoo.org/viewcvs.py/gentoo/xml/htdocs/doc/es/articles/l-sed3.xml?rev=1.1&content-type=text/plain |
1218 |
|
1219 |
Index: l-sed3.xml |
1220 |
=================================================================== |
1221 |
<?xml version='1.0' encoding="UTF-8"?> |
1222 |
<!-- $Header: /var/cvsroot/gentoo/xml/htdocs/doc/es/articles/l-sed3.xml,v 1.1 2007/11/02 14:41:56 yoswink Exp $ --> |
1223 |
<!DOCTYPE guide SYSTEM "/dtd/guide.dtd"> |
1224 |
|
1225 |
<guide link="/doc/es/articles/l-sed3.xml" disclaimer="articles" lang="es"> |
1226 |
<title>Sed mediante ejemplos, Parte 3</title> |
1227 |
|
1228 |
<author title="Autor"> |
1229 |
<mail link="drobbins@g.o">Daniel Robbins</mail> |
1230 |
</author> |
1231 |
<author title="Traductor"> |
1232 |
<mail link="LinuxBlues@×××××××××.org">LinuxBlues</mail> |
1233 |
</author> |
1234 |
|
1235 |
<abstract> |
1236 |
Sed es un poderoso y compacto editor de flujos de texto. En este artículo, el |
1237 |
segundo de la serie, Daniel muestra cómo realizar sustituciones de cadenas; |
1238 |
crear archivos de comandos más amplios y usar los comandos de sed para añadir, |
1239 |
insertar y modificar una línea. |
1240 |
</abstract> |
1241 |
|
1242 |
<!-- The original version of this article was published on IBM developerWorks, |
1243 |
and is property of Westtech Information Services. This document is an updated |
1244 |
version of the original article, and contains various improvements made by the |
1245 |
Gentoo Linux Documentation team --> |
1246 |
|
1247 |
<version>1.2</version> |
1248 |
<date>2005-10-09</date> |
1249 |
|
1250 |
<chapter> |
1251 |
<title>Subir de nivel: Manejo de datos, al estilo de sed</title> |
1252 |
<section> |
1253 |
<title>Muscular sed</title> |
1254 |
<body> |
1255 |
|
1256 |
<p> |
1257 |
En <uri link="l-sed2.xml">mi segundo artículo acerca de sed</uri>, ofrecí |
1258 |
ejemplos que mostraban el funcionamiento de sed, pero muy pocos de estos |
1259 |
ejemplos realizaban algo realmente útil. En este artículo final acerca de sed |
1260 |
es el momento de cambiar esto y poner a sed en buen uso. Mostraré algunos |
1261 |
ejemplos excelentes que no sólo mostrarán el extraordinario poder de sed, sino |
1262 |
que harán algunas cosas realmente elegantes y prácticas. Por ejemplo, en la |
1263 |
segunda mitad del artículo, mostraré cómo he diseñado un archivo de comandos |
1264 |
sed que convierte un archivo .QIF del programa de finanzas Quicken de Intuit en |
1265 |
un archivo de texto con buen formato. Antes de llegar a eso, veamos algunos |
1266 |
ejemplos menos complicados, aunque útiles, de archivos de comandos sed. |
1267 |
</p> |
1268 |
|
1269 |
</body> |
1270 |
</section> |
1271 |
<section> |
1272 |
<title>Traducción de texto</title> |
1273 |
<body> |
1274 |
|
1275 |
<p> |
1276 |
Nuestro primer ejemplo práctico, un archivo de comandos que convierte texto de |
1277 |
tipo UNIX a texto en el formato DOS/Windows. Como muy probablemente sabemos, el |
1278 |
texto de DOS/Windows contiene un CR (retorno de carro) y un LF (avance de |
1279 |
línea) al final de cada línea, mientras que el texto UNIX solamente tiene un |
1280 |
avance de línea. Pueden presentarse ocasiones en las que necesitemos mover |
1281 |
algún texto UNIX a un sistema Windows, y este archivo de comandos realizará los |
1282 |
pasos necesarios por nosotros. |
1283 |
</p> |
1284 |
|
1285 |
<pre caption="Conversión de formato entre UNIX y Windows"> |
1286 |
$ <i>sed -e 's/$/\r/' miunix.txt > midos.txt</i> |
1287 |
</pre> |
1288 |
|
1289 |
<p> |
1290 |
Con este comando, la expresión regular '$' apuntará al final de la línea, y la |
1291 |
'\r' le indica a sed que inserte un retorno de carro justo antes de llegar al |
1292 |
mismo. Insertamos un retorno de carro antes de un avance de línea y conseguido, |
1293 |
un CR/LF finaliza cada línea. Por favor, hay que considerar que '\r' únicamente |
1294 |
será reemplazado por un CR si se usa GNU sed 3.02.80 o posterior. Si aún no se |
1295 |
ha instalado GNU sed 3.02.80, ver <uri link="l-sed1.xml">mi primer artículo |
1296 |
acerca de sed</uri> para obtener las instrucciones necesarias. |
1297 |
</p> |
1298 |
|
1299 |
<p> |
1300 |
No sería capaz de enumerar todas las veces que he descargado algún archivo de |
1301 |
comandos de ejemplo o de código en C, para toparme con que estaba en el formato |
1302 |
DOS/Windows. Mientras que a algunos programas les trae sin cuidado manejar el |
1303 |
formato DOS/Windows CR/LF en archivos de texto, a otros les importa y mucho -- |
1304 |
un ejemplo a destacar sería bash que lo inicia tan pronto como encuentra un |
1305 |
retorno de carro. El siguiente comando sed convertirá texto con el formato |
1306 |
DOS/Windows al formato de confianza UNIX: |
1307 |
</p> |
1308 |
|
1309 |
<pre caption="Convertir código en C desde Windows a UNIX"> |
1310 |
$ <i>sed -e 's/.$//' midos.txt > miunix.txt</i> |
1311 |
</pre> |
1312 |
|
1313 |
<p> |
1314 |
El funcionamiento de este comando es muy simple: nuestra expresión regular a |
1315 |
sustituir coincide con el último carácter de la línea, el cual será un retorno |
1316 |
de carro. Lo reemplazamos con nada, dando lugar a que sea eliminado de la |
1317 |
salida completamente. Si usamos este comando y notamos que el último carácter |
1318 |
de cada línea ha sido eliminado, entonces habríamos especificado un archivo de |
1319 |
texto que ya estaba en formato UNIX, ¡por lo que no sería necesario! |
1320 |
</p> |
1321 |
|
1322 |
</body> |
1323 |
</section> |
1324 |
<section> |
1325 |
<title>Revertir de líneas</title> |
1326 |
<body> |
1327 |
|
1328 |
<p> |
1329 |
He aquí otra pequeña macro muy práctica. Con ella revertiremos las líneas en un |
1330 |
archivo, de forma muy similar a lo que realiza el comando "tac" que se incluye |
1331 |
en casi todas las distribuciones Linux. El nombre "tac" puede resultar confuso, |
1332 |
dado que "tac" no cambia el orden de los caracteres en una línea (de derecha a |
1333 |
izquierda), sino que cambia la posición de las líneas en un archivo (de abajo a |
1334 |
arriba). Hacerle un tac al siguiente archivo: |
1335 |
</p> |
1336 |
|
1337 |
<pre caption="Archivo de muestra"> |
1338 |
foo |
1339 |
bar |
1340 |
oni |
1341 |
</pre> |
1342 |
|
1343 |
<p> |
1344 |
....produce la siguiente salida: |
1345 |
</p> |
1346 |
|
1347 |
<pre caption="Archivo resultante"> |
1348 |
oni |
1349 |
bar |
1350 |
foo |
1351 |
</pre> |
1352 |
|
1353 |
<p> |
1354 |
Podemos hacer exactamente lo mismo con la siguiente macro en sed: |
1355 |
</p> |
1356 |
|
1357 |
<pre caption="Hacer lo mismo con una macro"> |
1358 |
$ <i>sed -e '1!G;h;$!d' avance.txt > retroceso.txt</i> |
1359 |
</pre> |
1360 |
|
1361 |
<p> |
1362 |
Encontraremos este comando especialmente útil si estamos en un sistema FreeBSD, |
1363 |
que no dispone del comando "tac". Aunque es muy práctica, es una muy buena idea |
1364 |
saber porqué hace lo que hace. Vamos a diseccionarlo. |
1365 |
</p> |
1366 |
|
1367 |
</body> |
1368 |
</section> |
1369 |
<section> |
1370 |
<title>Explicación de la reversión</title> |
1371 |
<body> |
1372 |
|
1373 |
<p> |
1374 |
En primer lugar, esta macro contiene tres comandos sed separados por puntos y |
1375 |
comas: '1!G', 'h' y '$!d'. Ahora es un buen momento para entender las |
1376 |
direcciones empleadas para el primer y el tercer comando. Si el primer comando |
1377 |
fuera '1G', la 'G' se aplicaría únicamente a la primera línea. De todas formas, |
1378 |
hay un carácter '!' adicional -- este carácter '!' niega el direccionamiento, |
1379 |
con lo que el comando 'G' se aplicará a todas las líneas excepto a la primera. |
1380 |
Con respecto a la '$!d' estamos en una situación muy similar. Si el comando |
1381 |
fuera '$d', lo aplicaría únicamente a la última línea del archivo (la dirección |
1382 |
'$' es una forma simple de designar a la última línea). De todas formas, con el |
1383 |
'!', '$!d' aplicará el comando 'd' a todas las líneas excepto a la última. |
1384 |
Ahora, lo único que necesitamos es entender qué es lo que hacen los comandos. |
1385 |
</p> |
1386 |
|
1387 |
<p> |
1388 |
Cuando ejecutamos nuestra macro para revertir las líneas, el primer comando que |
1389 |
se lleva a cabo es 'h'. Este comando le indica a sed que copie los contenidos |
1390 |
del espacio de patrones (la memoria intermedia que contiene la línea en la que |
1391 |
estamos trabajando) al espacio de mantenimiento (una memoria intermedia |
1392 |
temporal). Entonces se ejecuta el comando 'd', que elimina "foo" del espacio de |
1393 |
patrones, por lo que no se imprime después de que se ejecuten todos los |
1394 |
comandos para esta línea. |
1395 |
</p> |
1396 |
|
1397 |
<p> |
1398 |
Ahora, la segunda línea. Después de leer "bar" en el espacio de patrones, se |
1399 |
lleva a cabo el comando 'G', que añade los contenidos del espacio de |
1400 |
mantenimiento ("foo\n") al espacio de patrones ("bar\n"), dando como resultado |
1401 |
"bar\n\foo\n" en nuestro espacio de patrones. El comando 'h' vuelve a ponerlo |
1402 |
en el espacio de mantenimiento como medida de seguridad y 'd' borra la línea |
1403 |
del espacio de patrones, por lo que no se imprimirá. |
1404 |
</p> |
1405 |
|
1406 |
<p> |
1407 |
Para la última línea "oni", se repiten los mismos pasos, excepto que los |
1408 |
contenidos del espacio de patrones no se eliminan (debido al '$!' anterior a |
1409 |
'd') y los contenidos del espacio de patrones (tres líneas) se imprimen en |
1410 |
stdout. |
1411 |
</p> |
1412 |
|
1413 |
<p> |
1414 |
Ahora, es el momento de hacer una transformación de datos mucho más poderosa |
1415 |
con sed. |
1416 |
</p> |
1417 |
|
1418 |
</body> |
1419 |
</section> |
1420 |
<section> |
1421 |
<title>QIF mágico con sed</title> |
1422 |
<body> |
1423 |
|
1424 |
<p> |
1425 |
Durante las últimas semanas, he estado considerando comprar Quicken para hacer |
1426 |
balances en mis cuentas bancarias. Quicken es un buen programa de finanzas y |
1427 |
realizaría el trabajo con resultados brillantes. Pero, después de pensar acerca |
1428 |
de ello, decidí que podía escribir sin demasiados esfuerzos algún programa que |
1429 |
hiciera un balance de mi talonario. Después de todo, pensé, ¡soy un |
1430 |
desarrollador de software! |
1431 |
</p> |
1432 |
|
1433 |
<p> |
1434 |
Desarrollé un pequeño programa de balance de mi talonario (usando awk) que |
1435 |
calcula el balance manejando un archivo de texto que contenía todas mis |
1436 |
transacciones. Después de trabajar con el mismo, lo mejoré de forma que podía |
1437 |
tener en cuenta varias categorías de crédito y débito, tal y como Quicken podía |
1438 |
hacer. Pero había una característica más que quería añadir. He cambiado mis |
1439 |
cuentas recientemente a un banco que tiene una interfaz Web para manejar mis |
1440 |
cuentas en línea. Un día me dí cuenta de que el sitio web de mi banco me |
1441 |
permitía descargar la información de mi cuenta en formato .QIF; Acto seguido, |
1442 |
decidí que sería muy interesante convertir esa información a formato texto. |
1443 |
</p> |
1444 |
|
1445 |
</body> |
1446 |
</section> |
1447 |
<section> |
1448 |
<title>La historia de dos formatos</title> |
1449 |
<body> |
1450 |
|
1451 |
<p> |
1452 |
Antes de que veamos el formato QIF, he aquí el formato de mi archivo |
1453 |
talonario.txt: |
1454 |
</p> |
1455 |
|
1456 |
<pre caption="Mi talonario.txt"> |
1457 |
28 Aug 2000 food - - Y Supermarket 30.94 |
1458 |
25 Aug 2000 watr - 103 Y Check 103 52.86 |
1459 |
</pre> |
1460 |
|
1461 |
<p> |
1462 |
En mi archivo, todos los campos están separados por uno o más tabuladores, con |
1463 |
una transacción por línea. Después de la fecha, el siguiente campo lista el |
1464 |
tipo de gasto (o "-" si es un ingreso). El tercer campo lista el tipo de |
1465 |
ingreso (o "-" si es un gasto). Después hay un campo para el número de cheque |
1466 |
(de nuevo, con un "-" si no contiene nada), un campo de transacción realizada |
1467 |
("Y" o "N"), un comentario y el precio en dólares. |
1468 |
Ahora, estamos listos para echar un vistazo al formato QIF. Cuando vi el |
1469 |
archivo descargado con un visor de textos, esto es lo que pude observar: |
1470 |
</p> |
1471 |
|
1472 |
<pre caption="Ejemplo de formato QIF"> |
1473 |
!Type:Bank |
1474 |
D08/28/2000 |
1475 |
T-8.15 |
1476 |
N |
1477 |
PCHECKCARD SUPERMARKET |
1478 |
^ |
1479 |
D08/28/2000 |
1480 |
T-8.25 |
1481 |
N |
1482 |
PCHECKCARD PUNJAB RESTAURANT |
1483 |
^ |
1484 |
D08/28/2000 |
1485 |
T-17.17 |
1486 |
N |
1487 |
PCHECKCARD SUPERMARKET |
1488 |
</pre> |
1489 |
|
1490 |
<p> |
1491 |
Después de revisar el archivo, no fue demasiado complicado figurarse el formato |
1492 |
-- ignorando la primera línea, el formato es como sigue: |
1493 |
</p> |
1494 |
|
1495 |
<pre caption="Formato del archivo"> |
1496 |
D<fecha> |
1497 |
T<precio de la transacción> |
1498 |
N<número de cheque> |
1499 |
P<descripción> |
1500 |
^ |
1501 |
<comment>(este es el separador de campos)</comment> |
1502 |
</pre> |
1503 |
|
1504 |
</body> |
1505 |
</section> |
1506 |
<section> |
1507 |
<title>Comenzar el proceso</title> |
1508 |
<body> |
1509 |
|
1510 |
<p> |
1511 |
Cuando nos ponemos manos a la obra con un proyecto de sed como este, no hay que |
1512 |
desanimarse -- sed nos permite adecuar los datos gradualmente a su formato |
1513 |
final. A medida que progresamos en el mismo, podemos ir depurando nuestra macro |
1514 |
sed hasta que el resultado sea justo el que esperábamos. No es necesario |
1515 |
obtenerlo en el primer intento. |
1516 |
</p> |
1517 |
|
1518 |
<p> |
1519 |
Para comenzar, he creado un archivo denominado <path>qiftrans.sed</path> y he |
1520 |
comenzado a manipular los datos: |
1521 |
</p> |
1522 |
|
1523 |
<pre caption="qiftrans.sed"> |
1524 |
1d |
1525 |
/^^/d |
1526 |
s/[[:cntrl:]]//g |
1527 |
</pre> |
1528 |
|
1529 |
<p> |
1530 |
El primer comando '1d' elimina la primera línea, y el segundo elimina todos los |
1531 |
malditos caracteres '^' de la salida. La última línea elimina todos los |
1532 |
caracteres de control que puedan existir en el archivo. Dado que estoy |
1533 |
trabajando con un formato de archivos extraño, quiero evitar el riesgo de |
1534 |
encontrar cualquier carácter de control a lo largo del archivo. Ahora es el |
1535 |
momento de añadir mayor poder de procesamiento a esta macro tan básica: |
1536 |
</p> |
1537 |
|
1538 |
<pre caption="Macro básica mejorada"> |
1539 |
1d |
1540 |
/^^/d |
1541 |
s/[[:cntrl:]]//g |
1542 |
/^D/ { |
1543 |
s/^D\(.*\)/\1\tOUTY\tINNY\t/ |
1544 |
s/^01/Jan/ |
1545 |
s/^02/Feb/ |
1546 |
s/^03/Mar/ |
1547 |
s/^04/Apr/ |
1548 |
s/^05/May/ |
1549 |
s/^06/Jun/ |
1550 |
s/^07/Jul/ |
1551 |
s/^08/Aug/ |
1552 |
s/^09/Sep/ |
1553 |
s/^10/Oct/ |
1554 |
s/^11/Nov/ |
1555 |
s/^12/Dec/ |
1556 |
s:^\(.*\)/\(.*\)/\(.*\):\2 \1 \3: |
1557 |
} |
1558 |
</pre> |
1559 |
|
1560 |
<p> |
1561 |
Primero añado una dirección '/^D/' para que sed únicamente comience a procesar |
1562 |
cuando encuentra el primer carácter del campo de la fecha de un archivo QIF, |
1563 |
'D'. Todos los comandos entre las llaves se ejecutarán en orden tan pronto como |
1564 |
sed lea una de esas líneas en su espacio de patrones. |
1565 |
</p> |
1566 |
|
1567 |
<p> |
1568 |
La primera línea entre llaves transformará una línea como esta: |
1569 |
</p> |
1570 |
|
1571 |
<pre caption="Primera línea antes del cambio"> |
1572 |
D08/28/2000 |
1573 |
</pre> |
1574 |
|
1575 |
<p> |
1576 |
en otra que será como esta: |
1577 |
</p> |
1578 |
|
1579 |
<pre caption="Primera línea después del cambio"> |
1580 |
08/28/2000 OUTY INNY |
1581 |
</pre> |
1582 |
|
1583 |
<p> |
1584 |
Por supuesto, este formato no es perfecto por ahora, pero está bien. |
1585 |
Depuraremos gradualmente los contenidos del espacio de patrones al seguir. Las |
1586 |
siguientes 12 líneas realizan la labor de convertir la fecha en el formato con |
1587 |
tres letras, además, la última línea elimina las tres barras de la fecha. Con |
1588 |
lo cual obtenemos una línea como la siguiente: |
1589 |
</p> |
1590 |
|
1591 |
<pre caption="Aspecto final de la línea"> |
1592 |
Aug 28 2000 OUTY INNY |
1593 |
</pre> |
1594 |
|
1595 |
<p> |
1596 |
Los campos OUTY e INNY nos sirven como ubicaciones que se reemplazarán más |
1597 |
tarde. No puedo especificarlos ahora, porque si la cantidad de dólares es |
1598 |
negativa, querré indicar OUTY e INNY como "misc" y "-", mientras que si la |
1599 |
cantidad de dólares es positiva, querré indicarlos como "-" e "inco" |
1600 |
respectivamente. Dado que no se ha tenido acceso a la cantidad de dólares |
1601 |
todavía, prefiero usar ubicadores por ahora. |
1602 |
</p> |
1603 |
|
1604 |
</body> |
1605 |
</section> |
1606 |
<section> |
1607 |
<title>Depuración</title> |
1608 |
<body> |
1609 |
|
1610 |
<p> |
1611 |
Es el momento para depurarlo aún más: |
1612 |
</p> |
1613 |
|
1614 |
<pre caption="Mayor depuración"> |
1615 |
1d |
1616 |
/^^/d |
1617 |
s/[[:cntrl:]]//g |
1618 |
/^D/ { |
1619 |
s/^D\(.*\)/\1\tOUTY\tINNY\t/ |
1620 |
s/^01/Jan/ |
1621 |
s/^02/Feb/ |
1622 |
s/^03/Mar/ |
1623 |
s/^04/Apr/ |
1624 |
s/^05/May/ |
1625 |
s/^06/Jun/ |
1626 |
s/^07/Jul/ |
1627 |
s/^08/Aug/ |
1628 |
s/^09/Sep/ |
1629 |
s/^10/Oct/ |
1630 |
s/^11/Nov/ |
1631 |
s/^12/Dec/ |
1632 |
s:^\(.*\)/\(.*\)/\(.*\):\2 \1 \3: |
1633 |
N |
1634 |
N |
1635 |
N |
1636 |
s/\nT\(.*\)\nN\(.*\)\nP\(.*\)/NUM\2NUM\t\tY\t\t\3\tAMT\1AMT/ |
1637 |
s/NUMNUM/-/ |
1638 |
s/NUM\([0-9]*\)NUM/\1/ |
1639 |
s/\([0-9]\),/\1/ |
1640 |
} |
1641 |
</pre> |
1642 |
|
1643 |
<p> |
1644 |
Las siguientes siete líneas son un poco complicadas, por lo que las cubriremos |
1645 |
en detalle. Primero, encontramos tres comandos 'N' en una columna. El comando |
1646 |
'N' le indica a sed que lea la siguiente línea de la entrada y que la añada al |
1647 |
espacio de patrones actual. Los tres comandos 'N' dan lugar a que las tres |
1648 |
siguientes líneas se añadan a la memoria intermedia de nuestro espacio de |
1649 |
patrones actual, y ahora nuestra línea será como esta: |
1650 |
</p> |
1651 |
|
1652 |
<pre caption="Nuevo aspecto de nuestras líneas"> |
1653 |
28 Aug 2000 OUTY INNY \nT-8.15\nN\nPCHECKCARD SUPERMARKET |
1654 |
</pre> |
1655 |
|
1656 |
<p> |
1657 |
El espacio de patrones de sed se ha deteriorado -- necesitamos eliminar las |
1658 |
nuevas líneas adicionales y hacer cambios de formato adicionales. Para lograrlo |
1659 |
usaremos el comando de sustitución. El patrón que deseamos encontrar es el |
1660 |
siguiente: |
1661 |
</p> |
1662 |
|
1663 |
<pre caption="Eliminar líneas adicionales y aplicar un nuevo formato"> |
1664 |
'\nT.*\nN.*\nP.*' |
1665 |
</pre> |
1666 |
|
1667 |
<p> |
1668 |
Con ello apuntaremos a una nueva línea, seguida por una 'T', seguida de cero o |
1669 |
más caracteres, seguida por otra nueva línea, seguida por una 'N' con cualquier |
1670 |
número de caracteres, seguida por una 'P', seguida de cualquier número de |
1671 |
caracteres. Esta expresión regular coincidirá con las tres líneas que acabamos |
1672 |
de añadir al espacio de patrones. Pero queremos darle otro formato a esta |
1673 |
región, no reemplazarla por completo. La cifra en dólares, el número de cheque |
1674 |
(en caso de haberlo) y la descripción deben reaparecer en nuestra cadena de |
1675 |
reemplazo. Para hacerlo, subyugamos estas "partes interesantes" con paréntesis |
1676 |
de barra invertida, por lo que podemos hacer alusión a los mismos en nuestra |
1677 |
cadena de reemplazo (usando '\1', '\2\', y '\3' para indicar a sed dónde |
1678 |
insertarlos). Este es el comando final: |
1679 |
</p> |
1680 |
|
1681 |
<pre caption="Comando final"> |
1682 |
s/\nT\(.*\)\nN\(.*\)\nP\(.*\)/NUM\2NUM\t\tY\t\t\3\tAMT\1AMT/ |
1683 |
</pre> |
1684 |
|
1685 |
<p> |
1686 |
Este comando transforma nuestra línea en: |
1687 |
</p> |
1688 |
|
1689 |
<pre caption="Resultado del comando anterior"> |
1690 |
28 Aug 2000 OUTY INNY NUMNUM Y CHECKCARD SUPERMARKET AMT-8.15AMT |
1691 |
</pre> |
1692 |
|
1693 |
<p> |
1694 |
A pesar de que la línea está mejorando, hay algunas cosas que parecen a primera |
1695 |
vista... interesantes. La primera es la estúpida cadena "NUMNUM" -- ¿para qué |
1696 |
sirve? Lo veremos en las siguientes dos líneas de la macro sed, que |
1697 |
reemplazarán "NUMNUM" con un "-", mientras que "NUM"<number>"NUM" será |
1698 |
reemplazado con <number>. Como puede verse, subordinar el número de |
1699 |
cheque con una estúpida etiqueta nos permite insertar un "-" si el campo está |
1700 |
vacío. |
1701 |
</p> |
1702 |
|
1703 |
</body> |
1704 |
</section> |
1705 |
<section> |
1706 |
<title>Retoques finales</title> |
1707 |
<body> |
1708 |
|
1709 |
<p> |
1710 |
La última línea elimina un punto decimal a continuación de un número. Con lo |
1711 |
cual convertimos cifras en dólares como "3,231.00" en "3231.00", que es el |
1712 |
formato que empleo. Ha llegado el momento de echar un vistazo a la macro final: |
1713 |
</p> |
1714 |
|
1715 |
<pre caption="La macro final"> |
1716 |
1d |
1717 |
/^^/d |
1718 |
s/[[:cntrl:]]//g |
1719 |
/^D/ { |
1720 |
s/^D\(.*\)/\1\tOUTY\tINNY\t/ |
1721 |
s/^01/Jan/ |
1722 |
s/^02/Feb/ |
1723 |
s/^03/Mar/ |
1724 |
s/^04/Apr/ |
1725 |
s/^05/May/ |
1726 |
s/^06/Jun/ |
1727 |
s/^07/Jul/ |
1728 |
s/^08/Aug/ |
1729 |
s/^09/Sep/ |
1730 |
s/^10/Oct/ |
1731 |
s/^11/Nov/ |
1732 |
s/^12/Dec/ |
1733 |
s:^\(.*\)/\(.*\)/\(.*\):\2 \1 \3: |
1734 |
N |
1735 |
N |
1736 |
N |
1737 |
s/\nT\(.*\)\nN\(.*\)\nP\(.*\)/NUM\2NUM\t\tY\t\t\3\tAMT\1AMT/ |
1738 |
s/NUMNUM/-/ |
1739 |
s/NUM\([0-9]*\)NUM/\1/ |
1740 |
s/\([0-9]\),/\1/ |
1741 |
/AMT-[0-9]*.[0-9]*AMT/b fixnegs |
1742 |
s/AMT\(.*\)AMT/\1/ |
1743 |
s/OUTY/-/ |
1744 |
s/INNY/inco/ |
1745 |
b done |
1746 |
:fixnegs |
1747 |
s/AMT-\(.*\)AMT/\1/ |
1748 |
s/OUTY/misc/ |
1749 |
s/INNY/-/ |
1750 |
:done |
1751 |
} |
1752 |
</pre> |
1753 |
|
1754 |
<p> |
1755 |
Las siguientes once líneas adicionales usan la sustitución y alguna |
1756 |
funcionalidad de ramificación para perfeccionar la salida. Primero, deberíamos |
1757 |
observar esta línea: |
1758 |
</p> |
1759 |
|
1760 |
<pre caption="Primera línea en la que merece la pena fijarse"> |
1761 |
/AMT-[0-9]*.[0-9]*AMT/b fixnegs |
1762 |
</pre> |
1763 |
|
1764 |
<p> |
1765 |
Esta línea contiene un comando ramificado, que es de la forma "/expreg/b |
1766 |
etiqueta". Si se encuentra en el espacio de patrones la expreg, sed ramificará |
1767 |
la etiqueta fixnegs. Es muy sencillo encontrar esta etiqueta, que aparece en |
1768 |
el código como ":fixnegs". Si la expreg no coincide, continúa con normalidad y |
1769 |
sigue procesando el siguiente comando. |
1770 |
</p> |
1771 |
|
1772 |
<p> |
1773 |
Ahora que entendemos cómo funciona el comando, vamos a ver las ramas. Si |
1774 |
observamos la expresión regular ramificada, vemos que coincidirá con la cadena |
1775 |
'AMT', seguida de un '-', seguida de cualquier número de dígitos y 'AMT'. Como |
1776 |
es fácil figurarse, la expreg trata de forma especial las cantidades de dólares |
1777 |
negativas. Anteriormente subordinamos las cantidades de dólares con cadenas |
1778 |
'AMT' para que pudiésemos encontrarlas fácilmente después. Dado que la expreg |
1779 |
sólo coincidirá con cifras de dólares que comiencen con un '-', nuestra rama |
1780 |
sólo aparecerá cuando estemos manejando débitos. Si estamos manejando un débito |
1781 |
OUTY debe quedar como 'misc', INNY debe quedar como '-' y debe quitar el signo |
1782 |
negativo delante de la cantidad del débito. Si seguimos el código, veremos que |
1783 |
eso es lo que hace exactamente. Si el ramal no se ejecuta, OUTY será |
1784 |
reemplazado con un '-', e INNY se reemplazará por 'inco'. ¡Hemos terminado! La |
1785 |
línea resultante es perfecta ahora: |
1786 |
</p> |
1787 |
|
1788 |
<pre caption="Línea resultante perfecta"> |
1789 |
28 Aug 2000 misc - - Y CHECKCARD SUPERMARKET -8.15 |
1790 |
</pre> |
1791 |
|
1792 |
</body> |
1793 |
</section> |
1794 |
<section> |
1795 |
<title>No hay que confundirse</title> |
1796 |
<body> |
1797 |
|
1798 |
<p> |
1799 |
Como se ha visto, convertir datos usando sed no es tan complicado, siempre y |
1800 |
cuando afrontemos el problema de forma incremental. No hay que tratar de hacer |
1801 |
todo con un único comando sed, o todo a la primera. En lugar de esto, hay que |
1802 |
trabajar gradualmente hasta que logremos nuestro objetivo, y continuaremos |
1803 |
mejorando nuestra macro sed hasta que el resultado sea exactamente el que |
1804 |
deseábamos. Sed contiene muchos recursos, espero que pronto nos familiaricemos |
1805 |
con sed y con su funcionamiento interno y que continuemos creciendo en nuestro |
1806 |
dominio de sed |
1807 |
As you can see, converting data using sed isn't all that hard, as long as you |
1808 |
approach the problem incrementally. Don't try to do everything with a single sed |
1809 |
command, or all at once. Instead, gradually work your way toward the goal, and |
1810 |
continue to enhance your sed script until your output looks just the way you |
1811 |
want it to. Sed packs a lot of punch, and I hope that you've become very |
1812 |
familiar with its inner workings and that you'll continue to grow in your sed |
1813 |
mastery! |
1814 |
</p> |
1815 |
|
1816 |
<ul> |
1817 |
<li> |
1818 |
Leer los otros artículos acerca de sed de Daniel en developerWorks: "Sed |
1819 |
mediante ejemplos, <uri link="/doc/es/articles/l-sed1.xml">Parte 1</uri> y |
1820 |
<uri link="/doc/es/articles/l-sed2.xml">Parte 2</uri>. |
1821 |
</li> |
1822 |
<li> |
1823 |
Comprobar la excelente <uri |
1824 |
link="http://www.student.northpark.edu/pemente/sed/sedfaq.html">sed FAQ</uri> |
1825 |
de Eric Pement. |
1826 |
</li> |
1827 |
<li> |
1828 |
Se puede encontrar el código fuente de sed 3.02 en |
1829 |
<uri>ftp://ftp.gnu.org/pub/gnu/sed</uri>. |
1830 |
</li> |
1831 |
<li> |
1832 |
Se puede encontrar el nuevo sed 3.02.80 en <uri>ftp://alpha.gnu.org</uri>. |
1833 |
</li> |
1834 |
<li> |
1835 |
Eric Pement tiene también una lista muy práctica de <uri |
1836 |
link="http://www.student.northpark.edu/pemente/sed/sed1line.txt">sed one-liners</uri> |
1837 |
que cualquier aspirante a gurú sed debería consultar. |
1838 |
</li> |
1839 |
<!-- FIXME BOTH DEAD and no other locations, sorry |
1840 |
<li> |
1841 |
Maybe you'd like to read <uri |
1842 |
link="http://www.softlab.ntua.gr/unix/docs/sed.txt">7th edition UNIX's sed |
1843 |
man page</uri> (circa 1978!). |
1844 |
</li> |
1845 |
<li> |
1846 |
Take Felix von Leitner's short <uri |
1847 |
link="http://www.math.fu-berlin.de/~leitner/sed/tutorial.html">sed |
1848 |
tutorial</uri>. |
1849 |
</li> |
1850 |
<li> |
1851 |
Brush up on <uri link="http://vision.eng.shu.ac.uk/C++/misc/regexp/">using |
1852 |
regular expressions</uri> to find and modify patterns in text in this free, |
1853 |
dW-exclusive tutorial. |
1854 |
</li> |
1855 |
--> |
1856 |
</ul> |
1857 |
|
1858 |
</body> |
1859 |
</section> |
1860 |
</chapter> |
1861 |
|
1862 |
</guide> |
1863 |
|
1864 |
|
1865 |
|
1866 |
-- |
1867 |
gentoo-commits@g.o mailing list |