Issue
A sed and script problem needs to save
i want to write a script and do something like this the whole task is write a shell script and convert parameters to the command used by sed ,Then call sed to print the specified line from stdin .
seq 1 100 | ./script.sh 1 9 34-35
and get the answer with :
1 9 34 35
below is my code
#!/bin/bash
str="sed -n -e '"
data=$(cat)
#echo "$data"
for arg in $@;do
if [ `expr index $arg -` -eq 0 ]; then
str="$str${arg}p;"
else
len=`expr length $arg`
i=`expr index $arg -`
i=`expr $i - 1`
tmp1=`expr substr $arg 1 $i`
str="$str${tmp1},"
i=`expr $i + 2`
tmp2=`expr substr $arg $i $len`
str="$str${tmp2}p;"
fi
done
str="$str'"
echo "$str"
`echo $data | $str`
#echo `$str`
~
and i got the error sed: -e expression #1, char 1: unknown command: `''
what is the problem and how can i do this correct?
Solution
Your code builds a string.
With arguments 1
9
34-35
, you will get:
sed -n -e '1p;9p;34,35p;'
You call:
`echo $data | $str`
This becomes two commands piped together:
echo
with arguments:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
sed
with arguments:-n
-e
'1p;9p;34,35p;'
Note that the shell does no further manipulation of the words. In particular, quote-stripping has already happened (there were none before expansion).
So sed receives a script argument starting literally with '
.
'
is not a valid sed command, so the error is printed.
Note that $data
should have been quoted, otherwise the shell will strip out the newlines as shown above, and echo
when run will output only a single line.
Note also that if the sed had succeeded, the backticks will cause the shell to try to run its output as a new command. This seems very unlikely to be what you intended.
To fix your code, it would make more sense to avoid confusion by separating commands and arguments:
#!/bin/bash
str=
data=$(cat)
#echo "$data"
for arg in $@;do
if [ `expr index $arg -` -eq 0 ]; then
str="$str${arg}p;"
else
len=`expr length $arg`
i=`expr index $arg -`
i=`expr $i - 1`
tmp1=`expr substr $arg 1 $i`
str="$str${tmp1},"
i=`expr $i + 2`
tmp2=`expr substr $arg $i $len`
str="$str${tmp2}p;"
fi
done
echo `echo "$data" | sed -n -e "$str"`
And you can simplify / modernise to:
#!/bin/bash
str=
for arg; do
if [ $(expr index $arg -) -eq 0 ]; then
str="$str${arg}p;"
else
len=$(expr length $arg)
i=$(expr index $arg -)
i=$(expr $i - 1)
tmp1=$(expr substr $arg 1 $i)
str="$str${tmp1},"
i=$(expr $i + 2)
tmp2=$(expr substr $arg $i $len)
str="$str${tmp2}p;"
fi
done
# this command will already read from stdin, so no need to buffer the data
echo $(sed -n -e "$str")
expr
is rather tedious to use.
Making use of bash's built-in functionality you can simplify much further:
#!/bin/bash
str=
for arg; do
str=$str${arg/-/,}"p;"
done
echo $(sed -n "$str") # output is combined into single line
# for separate lines, just do: sed -n "$str"
Or with argument validation:
#!/bin/bash
str=
for arg; do
if ! [[ $arg =~ ^[0-9]+(-[0-9]+)?$ ]]; then
echo bad args 1>&2
exit 1
fi
str=$str${arg/-/,}"p;"
done
echo $(sed -n "$str")
Any of these versions produce the sample output from the question.
Answered By - jhnc Answer Checked By - Gilberto Lyons (WPSolving Admin)