0

I have many text files like these File1, File2, and File3. . . File100

Each file have the same header for example

>7:1234-5678
line 2
line 3
.
.

Each file corresponds to an individual, let's say

File1=Juan
File2=Pedro
File3=Carlos

What I want to do is add the name of each individual to the first line of each file. something like this:

>Juan_7:1234-5678
line 2
line 3
.
.

In other words: I have several text files (File1...File100), I have a keyfile with these filenames and the names (individuals) whom they belongs. I want to put those names (individuals) in the first line of each file. Does it makes more sense now?.

I have tried with the following code but it is probably wrong.

#!/bin/bash
File1="Juan";   File2="Pedro"; File3="Carlos"

for i in {1..3}; do
 for file in ./*.txt; do
 eval datafile="\$File$i" 
 sed -i -e '1 s/7:/'"$datafile"'_7:/g' ./File"$1".txt
done
done
John Kugelman
  • 307,513
  • 65
  • 473
  • 519
Fersal
  • 59
  • 5
  • It absolutely can be done, but maybe I am slow, but your question is not super clear. And users here will help you, but not write the whole thing for you. Define and explain your requirement better, and start working on it. If you don't even know how to start, I suggest https://ryanstutorials.net/bash-scripting-tutorial/ – Nic3500 Feb 28 '18 at 01:57
  • Put the comment in the question, code in the comments is hard to understand. – Nic3500 Feb 28 '18 at 02:50
  • You could look at this: https://stackoverflow.com/questions/9533679/how-to-insert-a-text-at-the-beginning-of-a-file – Nic3500 Feb 28 '18 at 02:56
  • If you look once on {1..3} and another time on the files, you will process each file 3 times... – Nic3500 Feb 28 '18 at 02:57

2 Answers2

1

By reading your code I'm confused if these are typing mistakes or real mistakes:

  1. Variable file is assigned (line 5), but called with $File (line 6)
  2. Line 6, variable $1 is called, but it is meaningless because it refers the first argument passed to this script, since you never do the passing, it gives null. Is it $i instead?

Other issues:

Line 7: No need to use 'g' as there is no more than one match

Cutting your expression into parts with single or double quotes are acceptable (As noted by @JohnKugelman), but, to pass variable to s/old/new/, it's unnecessary to quote the expression unless you need SPACE character in your expression. On the other hand, if there is a word-class character (letters, digits and underline "_") following the position of the variable, just embrace it:

sed -i "1s/7:/${datafile}_7:/" ./File$i.txt

Note for passing variables which contain special symbol like '/', '*', etc., to sed: You need to first escape all these symbols using parameter expansion. (C.f. external link Passing variables which contain special characters to sed and Bash manual Parameter expansion)

Issue about logic structures:

As @Nic3500 said about. The first for loop contain 3 loops on i; the second for loop contain n loops on your n files in the directory - in total 3*n loops. But your operation needs only n.

It is confusing since you did't say what is the relationship between the File$i.txt and the values "Juan". You just confound them in your example, where, "File1" is a variable but at the same time the file name of "File1.txt". If you really already have a sets of such variables (variable name = file name), you can just:

for i in {1..3}; do
sed -i "1s/7:/$(eval echo \$File$i)_7:/" ./File$i.txt
done

Same way as your script using dynamic variable names.

But this is really frustrating using variables as names of variables and I personally not recommend to. Instead, using an array, I think, is better:

NAME=(Juan Pedro Carlos); # Or other ways to assign this array
for((i=0;i<${#NAME[@]};i++)); do
sed -i "1s/7:/${NAME[$i]}_7:/" ./File$(($i+1)).txt
done
LDecem
  • 15
  • 5
  • @JohnKugelman Thanks for pointing out. I haven't tested on such thing, (neither do manual of sed?) apologize. It seems just necessary to put them all together w/o SPACE or the latter ones would be read as the input file? – LDecem Feb 28 '18 at 15:03
0

@LDecem, thanks for your answer, I must to say that many thing you pointed out are over my head. I actually found a script that do what I actually want to get. I don't know if the syntax is correct but it is working well. Regarding the names I just put them like an example but they are actually other kind of string.

The code I am talking about is:

File1=TLRP1; File2=TLRP4; File3=TLRP5

for i in {1..3}; do 
 for file in ./File"$i"_data.txt; do 
  eval datafile="\$File$i"
  sed -i -e '1 s/7:/'"$datafile"'_7:/g' ./File"$i"_data.txt 
 done 
done
Fersal
  • 59
  • 5