3

I want to repeat the input text 5 times and want to save in another text file.However in every repetition first and last line number only be changed.

My input text is:

READ 1 ALL
DMN 2,3 ^DTND
DEL 2,3
WRITE 1A ALL

OUTPUT:

READ 1 ALL
DMN 2,3 ^DTND
DEL 2,3
WRITE 1A ALL

READ 2 ALL
DMN 2,3 ^DTND
DEL 2,3
WRITE 2A ALL

READ 3 ALL
DMN 2,3 ^DTND
DEL 2,3
WRITE 3A ALL

READ 4 ALL
DMN 2,3 ^DTND
DEL 2,3
WRITE 4A ALL

READ 5 ALL
DMN 2,3 ^DTND
DEL 2,3
WRITE 5A ALL

I tried

#!/bin/sh
for file in `cat input.txt`
do
yes $file
done
manas
  • 479
  • 2
  • 14

6 Answers6

5

You could do this with Perl:

echo 'READ %s ALL
DMN 2,3 ^DTND
DEL 2,3
WRITE %sA ALL' | perl -0777 -nE '
for($x=1; $x<=5; $x++) { say sprintf $_, $x, $x }'

Or in awk:

echo 'READ %s ALL
DMN 2,3 ^DTND
DEL 2,3
WRITE %sA ALL' | awk -v RS= '{for(i=1;i<=5;i++) printf($0 "\n\n",i,i)}'

Same concept in the shell:

s='READ %s ALL
DMN 2,3 ^DTND
DEL 2,3
WRITE %sA ALL'

for i in {1..5}; do
    printf "$s\n\n" "$i" "$i"
done    

If you don't want to create a template for printf to use with %s for your replacements, I would use perl for the more precise regex available:

echo 'READ 1 ALL
DMN 2,3 ^DTND
DEL 2,3
WRITE 1A ALL' | perl -0777 -nE '
for($x=1; $x<=5; $x++) { 
    $s=$_; 
    $s=~s/^(READ |WRITE )(1)(?=\D|$)/$1$x/g; 
    say $s }'
dawg
  • 98,345
  • 23
  • 131
  • 206
2

Using GNU awk for gensub():

$ awk -v RS= -v ORS='\n\n' '{for (i=1; i<=5; i++) print gensub(/1/,i,"g")}' file
READ 1 ALL
DMN 2,3 ^DTND
DEL 2,3
WRITE 1A ALL

READ 2 ALL
DMN 2,3 ^DTND
DEL 2,3
WRITE 2A ALL

READ 3 ALL
DMN 2,3 ^DTND
DEL 2,3
WRITE 3A ALL

READ 4 ALL
DMN 2,3 ^DTND
DEL 2,3
WRITE 4A ALL

READ 5 ALL
DMN 2,3 ^DTND
DEL 2,3
WRITE 5A ALL
Ed Morton
  • 188,023
  • 17
  • 78
  • 185
1

for file in `cat input.txt` loops over the words in the input file.

yes $file will output the word forever, so your loop will never repeat.

Use a for loop to increment an index from 1 to 5. Then use sed to substitute that into the first and last lines of the file.

for i in {1..5}; do
    sed -e "s/(READ ).*( ALL)/\\1$i\\2/" -e "s/(WRITE ).*(A ALL)/\\1$i\\2/" input.txt
done
Barmar
  • 741,623
  • 53
  • 500
  • 612
1

Assuming you only want to replace only first and last 1 in string here is a gnu-awk solution:

awk -v RS= '
{
   print
   for (i=2; i<=5; ++i)
      print gensub(/^([^1]*)1(.*)1([^1]*)$/, "\\1" i "\\2" i "\\3", "1")
}' ORS='\n\n' file

READ 1 ALL
DMN 2,3 ^DTND
DEL 2,3
WRITE 1A ALL

READ 2 ALL
DMN 2,3 ^DTND
DEL 2,3
WRITE 2A ALL

READ 3 ALL
DMN 2,3 ^DTND
DEL 2,3
WRITE 3A ALL

READ 4 ALL
DMN 2,3 ^DTND
DEL 2,3
WRITE 4A ALL

READ 5 ALL
DMN 2,3 ^DTND
DEL 2,3
WRITE 5A ALL
anubhava
  • 761,203
  • 64
  • 569
  • 643
1

Using no programs / processes other than Bash:

repeat_file() {
  local -ir times="${1}"
  local -a lines first_line last_line
  readarray -t lines
  ((${#lines[@]} >= 2)) || return 2
  read -a first_line <<<"${lines[0]}"
  read -a last_line <<<"${lines[-1]}"
  unset 'lines[-1]'
  unset 'lines[0]'
  local -ar lines
  local -i idx
  local line
  for ((idx = 1;;)); do
    echo "${first_line[@]}"
    for line in "${lines[@]}"; do
      echo "${line}"
    done
    echo "${last_line[@]}"
    ((++idx > times)) && break
    ((++first_line[1]))
    last_line[1]="$(("${last_line[1]%A}" + 1))A"
    echo
  done
}

repeat_file 5 < input > output
Andrej Podzimek
  • 2,409
  • 9
  • 12
1

Another Perl solution:

Updated answer(thanks to dawg)

echo 'READ 1 ALL
DMN 2,3 ^DTND
DEL 2,3
WRITE 1A ALL' | perl -0777 -nE 'while($i++<5) { s/(\d)(?=A? ALL)/$i/g; say }'

Original answer

$ echo 'READ 1 ALL
DMN 2,3 ^DTND
DEL 2,3
WRITE 1A ALL' | perl -0777 -nE ' $_.="\n"; print; 
while($i++<=3) { s/(\d)(?=A? ALL)/$1+1/ge; print } '

Both print:

READ 1 ALL
DMN 2,3 ^DTND
DEL 2,3
WRITE 1A ALL

READ 2 ALL
DMN 2,3 ^DTND
DEL 2,3
WRITE 2A ALL

READ 3 ALL
DMN 2,3 ^DTND
DEL 2,3
WRITE 3A ALL

READ 4 ALL
DMN 2,3 ^DTND
DEL 2,3
WRITE 4A ALL

READ 5 ALL
DMN 2,3 ^DTND
DEL 2,3
WRITE 5A ALL
dawg
  • 98,345
  • 23
  • 131
  • 206
stack0114106
  • 8,534
  • 3
  • 13
  • 38
  • Well certainly it works in this case. I think the use of `e` is not really necessary and I would steer you towards `perl -0777 -nE 'while($i++<5) { s/(\d)(?=A? ALL)/$i/g; say }'` – dawg Aug 18 '21 at 18:31
  • aah.. nice, I was not pleasant to have 2 print statements.. and you fixed it.. thank you very much.. – stack0114106 Aug 18 '21 at 18:35
  • @dawg.. need your help on https://stackoverflow.com/questions/68868817/how-to-convert-mac-addr-to-int-using-awk/68876184#68876184 could you pls review it and suggest for improvements? – stack0114106 Aug 21 '21 at 19:37