Skip to content

Commit 61322e0

Browse files
authored
Sed awk improvements (#8)
* SED and AWK improvements * step
1 parent 4b8a4cf commit 61322e0

File tree

15 files changed

+2076
-165
lines changed

15 files changed

+2076
-165
lines changed

src/commands/awk/awk.functions.test.ts

Lines changed: 530 additions & 0 deletions
Large diffs are not rendered by default.

src/commands/awk/awk.test.ts

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,4 +418,206 @@ describe("awk command", () => {
418418
expect(result.exitCode).toBe(0);
419419
});
420420
});
421+
422+
describe("match() function with RSTART/RLENGTH", () => {
423+
it("should return position and set RSTART/RLENGTH", async () => {
424+
const env = new BashEnv({
425+
files: { "/data.txt": "hello foo world\n" },
426+
});
427+
const result = await env.exec(
428+
"awk '{print match($0, /foo/), RSTART, RLENGTH}' /data.txt",
429+
);
430+
expect(result.stdout).toBe("7 7 3\n");
431+
expect(result.exitCode).toBe(0);
432+
});
433+
434+
it("should return 0 when no match", async () => {
435+
const env = new BashEnv({
436+
files: { "/data.txt": "hello world\n" },
437+
});
438+
const result = await env.exec(
439+
"awk '{print match($0, /foo/), RSTART, RLENGTH}' /data.txt",
440+
);
441+
expect(result.stdout).toBe("0 0 -1\n");
442+
expect(result.exitCode).toBe(0);
443+
});
444+
});
445+
446+
describe("gensub() function", () => {
447+
it("should replace globally with g flag", async () => {
448+
const env = new BashEnv({
449+
files: { "/data.txt": "hello world\n" },
450+
});
451+
const result = await env.exec(
452+
'awk \'{print gensub(/o/, "0", "g")}\' /data.txt',
453+
);
454+
expect(result.stdout).toBe("hell0 w0rld\n");
455+
expect(result.exitCode).toBe(0);
456+
});
457+
458+
it("should replace Nth occurrence", async () => {
459+
const env = new BashEnv({
460+
files: { "/data.txt": "foo bar foo baz foo\n" },
461+
});
462+
const result = await env.exec(
463+
"awk '{print gensub(/foo/, \"XXX\", 2)}' /data.txt",
464+
);
465+
expect(result.stdout).toBe("foo bar XXX baz foo\n");
466+
expect(result.exitCode).toBe(0);
467+
});
468+
});
469+
470+
describe("power operator", () => {
471+
it("should compute power with ^", async () => {
472+
const env = new BashEnv({
473+
files: { "/data.txt": "test\n" },
474+
});
475+
const result = await env.exec("awk '{print 2^3}' /data.txt");
476+
expect(result.stdout).toBe("8\n");
477+
expect(result.exitCode).toBe(0);
478+
});
479+
480+
it("should compute power with **", async () => {
481+
const env = new BashEnv({
482+
files: { "/data.txt": "test\n" },
483+
});
484+
const result = await env.exec("awk '{print 3**2}' /data.txt");
485+
expect(result.stdout).toBe("9\n");
486+
expect(result.exitCode).toBe(0);
487+
});
488+
});
489+
490+
describe("FILENAME and FNR variables", () => {
491+
it("should track FILENAME", async () => {
492+
const env = new BashEnv({
493+
files: { "/data.txt": "line1\nline2\n" },
494+
});
495+
const result = await env.exec("awk '{print FILENAME, NR}' /data.txt");
496+
expect(result.stdout).toBe("/data.txt 1\n/data.txt 2\n");
497+
expect(result.exitCode).toBe(0);
498+
});
499+
500+
it("should reset FNR per file", async () => {
501+
const env = new BashEnv({
502+
files: {
503+
"/a.txt": "a1\na2\n",
504+
"/b.txt": "b1\nb2\n",
505+
},
506+
});
507+
const result = await env.exec(
508+
"awk '{print FILENAME, FNR, NR}' /a.txt /b.txt",
509+
);
510+
expect(result.stdout).toBe(
511+
"/a.txt 1 1\n/a.txt 2 2\n/b.txt 1 3\n/b.txt 2 4\n",
512+
);
513+
expect(result.exitCode).toBe(0);
514+
});
515+
});
516+
517+
describe("exit and next statements", () => {
518+
it("should exit with code", async () => {
519+
const env = new BashEnv({
520+
files: { "/data.txt": "line1\nline2\nline3\n" },
521+
});
522+
const result = await env.exec("awk 'NR==2{exit 5}' /data.txt");
523+
expect(result.exitCode).toBe(5);
524+
});
525+
526+
it("should skip to next line with next", async () => {
527+
const env = new BashEnv({
528+
files: { "/data.txt": "a\nb\nc\n" },
529+
});
530+
const result = await env.exec("awk '/b/{next}{print}' /data.txt");
531+
expect(result.stdout).toBe("a\nc\n");
532+
expect(result.exitCode).toBe(0);
533+
});
534+
});
535+
536+
describe("do-while loops", () => {
537+
it("should execute do-while at least once", async () => {
538+
const env = new BashEnv({
539+
files: { "/data.txt": "test\n" },
540+
});
541+
const result = await env.exec(
542+
"awk 'BEGIN{i=0; do{i++}while(i<3); print i}'",
543+
);
544+
expect(result.stdout).toBe("3\n");
545+
expect(result.exitCode).toBe(0);
546+
});
547+
});
548+
549+
describe("break and continue", () => {
550+
it("should break out of loop", async () => {
551+
const env = new BashEnv({
552+
files: { "/data.txt": "test\n" },
553+
});
554+
const result = await env.exec(
555+
"awk 'BEGIN{for(i=1;i<=10;i++){if(i==5)break; print i}}'",
556+
);
557+
expect(result.stdout).toBe("1\n2\n3\n4\n");
558+
expect(result.exitCode).toBe(0);
559+
});
560+
561+
it("should continue to next iteration", async () => {
562+
const env = new BashEnv({
563+
files: { "/data.txt": "test\n" },
564+
});
565+
const result = await env.exec(
566+
"awk 'BEGIN{for(i=1;i<=5;i++){if(i==3)continue; print i}}'",
567+
);
568+
expect(result.stdout).toBe("1\n2\n4\n5\n");
569+
expect(result.exitCode).toBe(0);
570+
});
571+
});
572+
573+
describe("printf formats", () => {
574+
it("should format hex with %x", async () => {
575+
const env = new BashEnv({
576+
files: { "/data.txt": "test\n" },
577+
});
578+
const result = await env.exec("awk 'BEGIN{printf \"%x\\n\", 255}'");
579+
expect(result.stdout).toBe("ff\n");
580+
expect(result.exitCode).toBe(0);
581+
});
582+
583+
it("should format octal with %o", async () => {
584+
const env = new BashEnv({
585+
files: { "/data.txt": "test\n" },
586+
});
587+
const result = await env.exec("awk 'BEGIN{printf \"%o\\n\", 8}'");
588+
expect(result.stdout).toBe("10\n");
589+
expect(result.exitCode).toBe(0);
590+
});
591+
592+
it("should format char with %c", async () => {
593+
const env = new BashEnv({
594+
files: { "/data.txt": "test\n" },
595+
});
596+
const result = await env.exec("awk 'BEGIN{printf \"%c\\n\", 65}'");
597+
expect(result.stdout).toBe("A\n");
598+
expect(result.exitCode).toBe(0);
599+
});
600+
601+
it("should format scientific with %e", async () => {
602+
const env = new BashEnv({
603+
files: { "/data.txt": "test\n" },
604+
});
605+
const result = await env.exec("awk 'BEGIN{printf \"%.2e\\n\", 1234}'");
606+
expect(result.stdout).toBe("1.23e+3\n");
607+
expect(result.exitCode).toBe(0);
608+
});
609+
});
610+
611+
describe("regex field separator", () => {
612+
it("should split on regex pattern", async () => {
613+
const env = new BashEnv({
614+
files: { "/data.txt": "a1b2c\n" },
615+
});
616+
const result = await env.exec(
617+
"awk -F'[0-9]+' '{print $1, $2, $3}' /data.txt",
618+
);
619+
expect(result.stdout).toBe("a b c\n");
620+
expect(result.exitCode).toBe(0);
621+
});
622+
});
421623
});

0 commit comments

Comments
 (0)