2

Create a file a.tsv with two lines

echo aa bbb ccc ddd >a.tsv
echo xxxxxxxaa bbb ccc ddd >>a.tsv

replace each line with dynamic generated string in a shell script a.sh

#!/bin/bash
#get line number
l1=$1
l2=$(expr $1 + 1)
#input file name
fn=$2
#get string in l1 line
vv="{${l1},${l1}p;${l2}q}"

v1=$(sed -n ${vv} $fn )
echo $v1
#cut off 6 chars from the end of string v1
v2=${v1::-6}
echo $v2
#replace l1 line v1 with new line v2
vb="{s|${v1}|${v2}|g }"
echo $vb

sed -i -r  '$vb'  $fn

when I run it as:

./a.sh 1 a.tsv

But I get those output:

What is wrong?

aa bbb ccc ddd
aa bbb c
{s|aa bbb ccc ddd|aa bbb c|g }
sed: -e expression #1, char 3: expected newer version of sed
chans
  • 109
  • 1
  • 9
  • See: [Difference between single and double quotes in bash](http://stackoverflow.com/q/6697753/3776858) – Cyrus Feb 05 '22 at 22:50

1 Answers1

0

The output of echo aa bbb ccc ddd >a.tsv is not a TSV (Tab-Separated Values) so don't name it a.tsv as that's misleading, use a.txt if you want it to have a suffix.

You can't easily do what you're trying to do robustly using sed since sed doesn't understand literal strings, see is-it-possible-to-escape-regex-metacharacters-reliably-with-sed. You should use a tool that does have literal string functions such as awk instead.

If I understand your code correctly it seems like this is what you're trying to do:

$ cat a.txt
aa bbb ccc ddd
xxxxxxxaa bbb ccc ddd

$ cat a.sh
#!/usr/bin/env bash

awk -i inplace -v lineNr="$1" '
    NR == lineNr {
        $0 = substr($0,1,length()-6)
    }
    { print }
' "$2"

$ ./a.sh 1 a.txt

$ cat a.txt
aa bbb c
xxxxxxxaa bbb ccc ddd

The above is using GNU awk for -i inplace, just like you were using GNU sed for -i (and -r), but unlike a sed solution, it'll work for any characters in the input.

Ed Morton
  • 188,023
  • 17
  • 78
  • 185