Home > front end >  Shell: Add string to the end of each line, which match the pattern. Filenames are given in another f
Shell: Add string to the end of each line, which match the pattern. Filenames are given in another f

Time:09-17

I'm still new to the shell and need some help.

  1. I have a file stapel_old.
  2. Also I have in the same directory files like english_old_sync, math_old_sync and vocabulary_old_sync.

The content of stapel_old ist:

english  
math  
vocabulary

The content of e.g. english is:

basic_grammar.md  
spelling.md  
orthography.md

I want to manipulate all files which are given in stapel_old like in this example:

  1. take the first line of stapel_old 'english', (after that math, and so on)
  2. convert in this case english to english_old_sync, (or after that what is given in second line, e.g. math to math_old_sync)
  3. search in english_old_sync line by line for the pattern '.md'
  4. And append to each line after .md :::#a1

The result should be e.g. of english_old_sync:

basic_grammar.md:::#a1
spelling.md:::#a1  
orthography.md:::#a1

of math_old_sync:

geometry.md:::#a1
fractions.md:::#a1

and so on. stapel_old should stay unchanged.

How can I realize that? I tried with sed -n, while loop (while read -r line), and I'm feeling it's somehow the right way - but I still get errors and not the expected result after 4 hours inspecting and reading.
Thank you!

EDIT
Here is the working code (The files are stored in folder 'olddata'):

clear
echo -e "$(tput setaf 1)$(tput setab 7)Learning directories:$(tput sgr 0)\n"
# put here directories which should not become flashcards, command: | grep -v 'name_of_directory_which_not_to_learn1' | grep -v 'directory2'
ls ../ | grep -v 00_gliederungsverweise | grep -v 0_weiter | grep -v bibliothek | grep -v notizen | grep -v Obsidian | grep -v z_nicht_uni | tee olddata/stapel_old

# count folders
echo -ne "\nHow much different folders: " && wc -l olddata/stapel_old | cut -d' ' -f1 | tee -a olddata/stapel_old
echo -e "Are this learning directories correct? [j ODER y]--> yes; [Other]-->no\n"
read lernvz_korrekt
if [ "$lernvz_korrekt" = j ] || [ "$lernvz_korrekt" = y ];
then
    read -n 1 -s -r -p "Learning directories correct. Press any key to continue..."
else
    read -n 1 -s -r -p "Learning directories not correct, please change in line 4. Press any key to continue..."
    exit
fi
echo -e "\n_____________________________\n$(tput setaf 6)$(tput setab 5)Found cards:$(tput sgr 0)$(tput setaf 6)\n"


#GET && WRITE FOLDER NAMES into olddata/stapel_old
anzahl_zeilen=$(cat olddata/stapel_old |& tail -1)

#GET NAMES of .md files of every stapel and write All to 'stapelname'_old_sync
i=0
name="var_$i"

for (( num=1; num <= $anzahl_zeilen; num   ))
do
    i="$((i   1))"
    name="var_$i"
    name=$(cat olddata/stapel_old | sed -n "$num"p)
    find ../$name/ -name '*.md' | grep -v trash | grep -v Obsidian | rev | cut -d'/' -f1 | rev | tee olddata/$name"_old_sync"
done
(tput sgr 0)

I tried to add:

input="olddata/stapel_old"
while IFS= read -r line
do
    sed -n "$line"p olddata/stapel_old
done < "$input"

The code to change only the english_old_sync is:

lines=$(wc -l olddata/english_old_sync | cut -d' ' -f1)
for ((num=1; num <= $lines; num  ))
do
    content=$(sed -n "$num"p olddata/english_old_sync)
    sed -i "s/"$content"/""$content":::#a1/g"" olddata/english_old_sync
done

So now, this need to be a inner for-loop, of a outer for-loop which holds the variable for english, right?

CodePudding user response:

stapel_old should stay unchanged.

You could try a while read loop and embed sed inside the loop.

#!/usr/bin/env bash

while IFS= read -r files; do
  echo cp -v "$files" "${files}_old_sync" &&
  echo sed '/^.*\.md$/s/$/:::#a1/' "${files}_old_sync"
done < olddata/staple_old

convert in this case english to english_old_sync, (or after that what is given in second line, e.g. math to math_old_sync)

  • cp copies the file with a new name, if the goal is renaming the original file name from the content of the file staple_old then change cp to mv

  • The -n and -i flag from sed was ommited , include it, if needed.

  • The script also assumes that there are no empty/blank lines in the content of staple_old file. If in case there are/is add an addition test after the line where the do is.

    [[ -n $files ]] || continue

  • It also assumes that the content of staple_old are existing files. Just in case add an additional test.

    [[ -e $files ]] || { printf >&2 '%s no such file or directory.\n' "$files"; continue; }


Or an if statement.

if [[ ! -e $files ]]; then
   printf >&2 '%s no such file or directory\n' "$files"
   continue
fi

  • See also help test

  • See also help continue


Combining them all together should be something like:

#!/usr/bin/env bash

while IFS= read -r files; do
  [[ -n $files ]] || continue
  [[ -e $files ]] || {
     printf >&2 '%s no such file or directory.\n' "$files"
     continue
  }
  echo cp -v "$files" "${files}_old_sync" &&
  echo sed '/^.*\.md$/s/$/:::#a1/' "${files}_old_sync"
done < olddata/staple_old

  • Remove the echo's If you're satisfied with the output so the script could copy/rename and edit the files.
  • Related