Using variables in terminal - bash

I wrote this code:
cat /etc/passwd | cut -d : -f1 | sed -n "${FT_LINE1}, ${FT_LINE2} p"
Output:
sed: -e expression #1, char 1: unknown command: `,'
But I have a problem with variables $FT_LINE1, $FT_LINE2.
When I use constants instead of a variables, this code works correctly
cat /etc/passwd | cut -d : -f1 | sed -n "3, 5 p"
I tried to use these constructions:
sed -n -e "${FT_LINE1}, ${FT_LINE2} p"
sed -n "{$FT_LINE1}, {$FT_LINE2} p"
sed -n "${FT_LINE1},${FT_LINE2} p"
sed -n "${FT_LINE1}, ${FT_LINE2}" p
sed -n "$FT_LINE1, $FT_LINE2" p
but the error remained.

As noted in melpomene and PesaThe's comments, sed address ranges can't be blank, both shell variables ${FT_LINE1}, and ${FT_LINE2}, must be set to some appropriate value.
This simplest way to reproduce the error is:
sed ,
Which outputs:
sed: -e expression #1, char 1: unknown command: `,'
Because , is not a sed command, it's just a delimiter that separates range addresses.
It might help to look at some other related errors. Let's add a starting address of 1:
sed 1,
Output:
sed: -e expression #1, char 2: unexpected `,'
Which seems unhelpful, since it should be expecting an address after the ,. Now let's add a second address of 1:
sed 1,1
Output:
sed: -e expression #1, char 3: missing command
A little better, but really it's char 4 that's missing a command, or rather there's a missing command after char 3.
Now let's add a command, and a bit of input and it works:
echo foo | sed 1,1p
Output:
foo

Related

Using sed to remove prefix with slash from string

I'm extracting a Jira issue from a string using sed. I want to get rid of prefixes too.
My possible prefixes are:
FEATURE_PREFIX="feature/"
BUGFIX_PREFIX="bugfix/"
I've tried three different ways to use sed despite the slash in the prefix but nothing seems to work.
First try:
export UNFIXED_ID=$(echo ${CI_MERGE_REQUEST_TITLE} | sed -e "s~^$BUGFIX_PREFIX~/" | sed -e "s~^$FEATURE_PREFIX~/")
export MERGE_REQUEST_JIRA_ID=$(echo ${UNFIXED_ID} | sed -r "s/^([A-Za-z][A-Za-z0-9]+-[0-9]+).*/\1/")
echo ${MERGE_REQUEST_JIRA_ID}
gives the error sed: unmatched '~'
Second try:
export UNFIXED_ID=$(echo ${CI_MERGE_REQUEST_TITLE} | sed -e "s~^$BUGFIX_PREFIX/~" | sed -e "s~^$FEATURE_PREFIX/~")
export MERGE_REQUEST_JIRA_ID=$(echo ${UNFIXED_ID} | sed -r "s/^([A-Za-z][A-Za-z0-9]+-[0-9]+).*/\1/")
echo ${MERGE_REQUEST_JIRA_ID}
gives the error sed: unmatched '~'
Third try:
export UNFIXED_ID=$(echo ${CI_MERGE_REQUEST_TITLE} | sed -e "s~^$BUGFIX_PREFIX~" | sed -e "s~^$FEATURE_PREFIX~")
export MERGE_REQUEST_JIRA_ID=$(echo ${UNFIXED_ID} | sed -r "s/^([A-Za-z][A-Za-z0-9]+-[0-9]+).*/\1/")
echo ${MERGE_REQUEST_JIRA_ID}
gives the error sed: unmatched '~'
As per this question Sed error : bad option in substitution expression I thought it was just a matter of replacing the / by ~
What am I failing to do here with the delimiter?
I apologise if I have misunderstood the question, but if the two variables are on their own lines, then you can probably just search for and print the entire line:-
sed -n '/FEATURE_PREFIX/p' file | \
cut -d'=' -f2 | \
head -c -3 | \
sed s'#$#\"#'

Getting errors when using variables with sed, but getting desired result on command line

I have in my bash script a line of code:
url=$(echo "$url" | sed -r 's#{$regex}#\2\3.v1\4#')
where:
url = " - https://ci-files.gr4bb.com/templates/v2/kubeval.src.yml"
regex = ^(.*)(https://ci-files\.gr4bb\.com/)templates/v2/(.+)(\.ya?ml)$
This line will fail with error:
sed: -e expression #1, char 21: Invalid preceding regular expression
The char 21 position would correspond to the letter 'e' in the regex.
However, if I run this on the command line:
echo " - https://ci-files.gr4bb.com/templates/v2/kubeval.src.yml" | sed -r 's#^(.*)(https://ci-files.gr4bb.com/)templates/v2/(.+)(\.ya?ml)$#\2\3.v1\4#'
I get the desired result, which is:
https://ci-files.gr4bb.com/kubeval.src.v1.yml
If I replace the single quotes with double quotes in the expression:
url=$(echo "$url" | sed -r "s#{$regex}#\2\3.v1\4#")
I get a different error:
sed: -e expression #1, char 32: invalid reference \4 on `s' command's RHS
Can someone please explain what is going on exactly?
Unless you want to match actual braces, {$regex} should be ${regex} or just $regex.
Parameter expansion doesn't happen inside single-quotes (').
Try:
echo "$url" | sed -r 's#'"$regex"'#\2\3.v1\4#'
or (backslash is not special when followed by a digit):
echo "$url" | sed -r "s#$regex#\2\3.v1\4#"

output of sed gives strange result when using capture groups

I'm doing the following command in a bash:
echo -e 'UNUSED\nURL: ^/tags/0.0.0/abcd' | sed -rn 's#^URL: \^/tags/([^/]+)/#\1#p'
I think this should output only the matching lines and the content of the capture group. So I'm expecting 0.0.0 as the result. But I'm getting 0.0.0abcd
Why contains the capture group parts from the left and the right side of the /? What I am doing wrong?
echo -e 'UNUSED\nURL: ^/tags/0.0.0/abcd' |
sed -rn 's#^URL: \^/tags/([^/]+)/#\1#p'
echo outputs two lines:
UNUSED
URL: ^/tags/0.0.0/abcd
The regular expression given to sed does not match the first line, so this line is not printed. The regular expression matches the second line, so URL: ^/tags/0.0.0/ is replaced with 0.0.0; only the matched part of the line is replaced, so abcd is passed unchanged.
To obtain the desired output you must also match abcd, for example with
sed -rn 's#^URL: \^/tags/([^/]+)/.*#\1#p'
where the .* eats all characters to the end of the line.
You can use awk:
echo -e 'UNUSED\nURL: ^/tags/0.0.0/abcd' | awk -F/ 'index($0, "^/tags/"){print $3}'
0.0.0
This awk command uses / as field delimiter and prints 3rd column when there ^/tags/ text in input.
Alternatively, you can use gnu grep:
echo -e 'UNUSED\nURL: ^/tags/0.0.0/abcd' | grep -oP '^URL: \^/tags/\K([^/]+)'
0.0.0
Or this sed:
echo -e 'UNUSED\nURL: ^/tags/0.0.0/abcd' | sed -nE 's~^URL: \^/tags/([^/]+).*~\1~p'
0.0.0
This sed catch your desired output.
echo -e 'UNUSED\nURL: ^/tags/0.0.0/abcd' | sed -E '/URL/!d;s#.*/(.*)/[^/]*#\1#'

BASH sed does not evaluate array

So i have an array with filenames.
for i in "${!array_FILE[#]}"; do
printf "%s\t%s\n" "$i" "${array_FILE[$i]}"
sed -e "s/\${USERNAME_VAR}/$USERNAME_VAR/" -e "s/\${USERNAME}/$USERNAME/" template > array_FILE[$i].js
done
The printf works and gives me
0 app_calander
1 app_contacts
2 app_search
3 app_index
but the files created are:
array_FILE[0].js
array_FILE[1].js
array_FILE[2].js
array_FILE[3].js
instead of
app_calander.js
app_contacts.js
app_search.js
app_index.js
If you can help me i appreciate it, it has to be changed by index because i have two array and i need to change values at the same index.
My temporary solution is:
filename="${array_FILE[$i]}"
sed -e "s/\${USERNAME_VAR}/$USERNAME_VAR/" -e "s/\${USERNAME}/$USERNAME/" template > $filename.js
but i was wondering if there is a better way!
REAL ISSUE
Now the real issue is when i try to pass a URL
for i in "${!array_FILE[#]}"; do
#printf "%s\t%s\n" "$i" "${array_FILE[$i]}"
filename="${array_FILE[$i]}"
url="${array_URL[$i]}"
sed -e "s/\${USERNAME_VAR}/$USERNAME_VAR/" -e "s/\${USERNAME}/$USERNAME/" -e "s/\${URL}/'$url'/" template > $filename.js
done
sed: -e expression #3, char 18: unknown option to `s'
sed: -e expression #3, char 18: unknown option to `s'
sed: -e expression #3, char 18: unknown option to `s'
sed: -e expression #3, char 18: unknown option to `s'
sample value of url is URL:https://example.com/app/index.html
EDIT FOR CLARIFICATION
data.txt
USERNAME_VAR:input_username
USERNAME:user01
PASSWORD_VAR:input_password
PASSWORD:password1
SUBMIT:submit
AUTH:cas
URL:https://example.com/app/calander.html
FILE:app_calander
URL:https://example.com/app/contacts.html
FILE:app_contacts
URL:https://example.com/app/search.html
FILE:app_search
URL:https://example.com/app/index.html
FILE:app_index
template
${USERNAME_VAR} = ${USERNAME}
${SUBMIT} IS TRUE
${PASSWORD_VAR} = ${PASSWORD}
${AUTH} = AUTH IS
URL TO HIT IS ${URL}
inject.sh
#!/bin/bash
USERNAME_VAR=($(grep -o 'USERNAME_VAR.*' data.txt | cut -f2- -d':'))
USERNAME=($(grep -o 'USERNAME.*' data.txt | grep -v 'VAR.*' | cut -f2- -d':'))
echo $USERNAME_VAR
echo $USERNAME
array_URL=($(grep -o 'URL.*' data.txt | cut -f2- -d':'))
array_FILE=($(grep -o 'FILE.*' data.txt | cut -f2- -d':'))
for i in "${!array_FILE[#]}"; do
#printf "%s\t%s\n" "$i" "${array_FILE[$i]}"
FILENAME="${array_FILE[$i]}"
URL="${array_URL[$i]}"
echo $URL
sed -e "s/\${URL}/$URL/" -e "s/\${USERNAME_VAR}/$USERNAME_VAR/" -e "s/\${USERNAME}/$USERNAME/" template > $FILENAME.js
done
Continuing from the comment, you could do something like:
for i in "${!array_FILE[#]}"; do
#printf "%s\t%s\n" "$i" "${array_FILE[$i]}"
filename="${array_FILE[$i]}"
url="${array_URL[$i]}"
sed -e "s#\${USERNAME_VAR}#$USERNAME_VAR#" \
-e "s#\${USERNAME}#$USERNAME#" \
-e "s#\${URL}#$url#" template > $filename.js
done
The answer to the first question is staring right at you: "${array_FILE[$i]}" is obviously different from "array_FILE[$i]"
To understand the "REAL ISSUE", just look at the error messages. They are telling you the problem is with the third sed expression, which assumes that $url does not have a "/" in it.
Unless you are certain that $USERNAME, $USERNAME_VAR and $url do not have "/" in them, then those sed commands will not work in the way you seem to expect.

bash : sed : regex in variable

I'm getting totally crazy with the following script.
The following command works as expected :
echo a | sed 's/a/b/'
Output :
b
But this script doesn't :
test="'s/a/b/'"
echo a | sed $test
Output :
sed: -e expression #1, char 1: unknown command : `''
I should really be stupid, but I don't see what I am missing.
Thanks,
test="'s/a/b/'"
echo a | sed $test
is equivalent to:
test="'s/a/b/'"
echo a | sed "'s/a/b/'"
Obviously sed doesn't understand the command with both " and ', It interprets ' as a command. You can use either one of them:
test='s/a/b/'
Or
test='s/a/b/'
This is because your double wrapping your string. test="'s/a/b'". Sed then gets 's/a/b/' as literal string. You only want sed to receive s/a/b/.
You only need to wrap the string in one set of quotes, otherwise the inner set of quotes will be interpreted as part of the argument.
you may want this:
kent$ test="s/a/b/"
kent$ echo a | sed ${test}
b
or
kent$ echo a | sed $test
b
or
test=s/a/b/

Resources