Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

Suppose that I have ten bash shell scripts: script1.sh, script2.sh, ..., script10.sh. Initially, all ten files are identical.

Now, I would like to make two changes in each script:

  1. In each file, I would like to change a particular line (say line 8) -- that is, deleting whatever is on line 8 and replacing it with a "constant" string that I specify, such as "This is line 8." This is similar to this question, but there they wanted to replace "AAA" with "BBB", whereas I would like to replace line 8 (whatever it is) with "This is line 8.".

  2. In each file, I would like to change another particular line (say line 21) and replace it with a "variable" string that I specify. For example, in script1.sh I want to change line 21 to "XYZ"; in script2.sh I want to change line 21 to "PQR"; and in script3.sh I want to change line 21 to "ABC". Essentially this is just many calls to the function in (1) above -- except that I would be making the change in one individual file rather than in all files, and that I am specifying ten different strings rather than just one. So to obtain (2) here, perhaps I would just call (1) ten different times with different parameters.

I am interested in solutions that use commonly available Linux programs like bash, vi, awk, gawk, etc.

share|improve this question

3 Answers 3

up vote 5 down vote accepted
for file in f1 f2; do
  sed -i '8s/^.*$/foo/' "$file"
done
share|improve this answer
3  
Why not just sed -i '8s/^.*$/foo/' f1 f2? –  l0b0 Jun 21 '13 at 21:51
    
@l0b0 Have you tried that? –  Hauke Laging Jun 21 '13 at 21:59
2  
Worked perfectly: echo test1 > f1; echo test2 > f2; sed -i '1s/^.*$/foo/' f1 f2. cat f1 f2 shows that both were changed to foo. –  l0b0 Jun 21 '13 at 22:05
    
@l0b0 That's funny. I tried that first but without -i. And in that case just one line was changed. Doesn't make sense to me. A bug (GNU sed-Version 4.2.1)? –  Hauke Laging Jun 21 '13 at 22:10
2  
Try with -s: "consider files as separate rather than as a single continuous long stream." –  l0b0 Jun 22 '13 at 8:28

Using awk

for file in script1.sh script2.sh script3.sh ... script10.sh; do
    temp=$(mktemp)
    awk '
        BEGIN {
            line8 = "This is line 8"
            line21["script1.sh"] = "XYZ"
            line21["script2.sh"] = "PQR"
            line21["script3.sh"] = "ABC"
            # ... 
        }
        FNR == 8 { print line8; next }
        FNR == 21 && FILENAME in line21 { print line21[FILENAME]; next }
        {print}
    '  "$file" > "$temp" && mv "$temp" "$file"
done

or, using bash and sed

# bash variables to store new values. requires bash v4 for the associative array
line8="This is line 8"
declare -A line21=(
    [script1.sh]="XYZ"
    [script2.sh]="PQR"
    [script3.sh]="ABC"
    # ...
)
# then use sed
for file in script1.sh script2.sh script3.sh ... script10.sh; do
    sed -i "8s/.*/$line8/; 21s/.*/${line21[$file]}/" "$file"
done

With the sed solution, you have to be careful that the new lines do not contain "/" characters, as that will break the s/// command. Although you can use different delimiter characters, such as s|pattern|replacement| (in which case the same warning applies, recursively)

ed works too:

for file in script1.sh script2.sh script3.sh ... script10.sh; do
    ed "$file" <<ED_COMMANDS
8d
8i
$line8
.
21d
21i
${line21[$file]}
.
w
q
ED_COMMANDS
done
share|improve this answer

I will answer both questions but, as a general rule, please don't combine questions like this, split them into separate posts instead.

Question 1

  1. Perl:

    for f in *.sh; do 
      perl -i -lne '$.==8 ? print "This is line 8" : print;' "$f"; 
    done
    
  2. awk and variants:

    for f in *.sh; do 
      awk '{if(NR==8){print "This is line 8"}else{print}}' "$f" > fifo && 
      mv fifo "$f";
    done
    

Question 2

I would first create a file with the replacements I want to make. For example:

script1.sh  foo1
script2.sh  foo2
script3.sh  foo3
script4.sh  foo4

Then read that file to perform the substitutions:

while read f s; do 
 export s;
 perl -i -lne '$.==8 ? print "$ENV{s}" : print;' "$f";
done < sublist.txt
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.