Assigning the output of a bash string manipulation to a variable [duplicate] - bash

This question already has answers here:
How do I set a variable to the output of a command in Bash?
(15 answers)
Closed 5 years ago.
On Ubuntu 16.04, I have a bash script which I run as root. I want to remove all spaces from the user's input, and assign the trimmed string to a variable.
read -p "Enter username: " USERNAME
echo "$USERNAME" | sed s/' '/''/g
TRIM="$USERNAME" | sed s/' '/''/g
echo $TRIM
echo "Done"
Here's some sample input and output:
Enter username: h j k l
hjkl
Done
$TRIM is empty.
What change do I need to make to get $TRIM to contain the result?

Use $() to capture the output of a command.
trim=$(echo "$USERNAME" | sed 's/ //g')
However, you don't need a command for this, you can use the bash parameter expansion operator to do substitution.
trim=${username// /}
P.S. Don't use uppercase variable names, they're conventionally reserved for environment variables.

There are a couple of things you should note with your script.
First of all, uppercase identifiers like USERNAME are usually reserved for environment variables. So you might well override a shell variable accidentally that causes undesired effects. Same is the case with TRIM.
Secondly, you should check the default shell in your Ubuntu distribution using the SHELL built-in. Do something like
echo $SHELL
If the output is dash or bash, you could use command substitution to achieve your objective.
trim=$(echo "$username" | sed 's/ //g')
Mind that the sed commands themselves should be put under the single quotes.
When you echo trim, use double quotes to prevent word splitting like
echo "$trim" # In your case though the double quotes doesn't make any difference

Related

How to assign string outputs of expressions in variables without echo? [duplicate]

This question already has answers here:
How to pass the value of a variable to the standard input of a command?
(9 answers)
Closed 1 year ago.
I am currently saving string outputs from expressions like so
SOME_PATH="/some/path/file"
FILE_NAME=`echo "$SOME_PATH" | rev | cut -f 1 -d "/" | rev )`
FILE_FOLDER=`echo "$SOME_PATH" | sed s/$FILE_NAME//`
echo ${SOME_PATH}
echo ${FILE_NAME}
echo ${FILE_FOLDER}
which seems like the echo is superfluous, but I couldn't get it to work without it. What is the preferred way?
What is the preferred way?
The preferred way is to use variable expansions.
somepath='/some/path'
filename=${somepath##*/}
dirname=${somepath%/*}
Also: do not use backticks `, prefer $(...), quote variable expansions "s/$FILE_NAME//", prefer to use lower case variables for local variables and check your scripts with shellcheck.
How to assign string outputs of expressions in variables without echo?
Use here string to save one fork() call.
var=$(<<<"$var" command)

Bash/Shell: Why am I getting the wrong output for if-else statements? [duplicate]

I'm writing a shell script that should be somewhat secure, i.e., does not pass secure data through parameters of commands and preferably does not use temporary files. How can I pass a variable to the standard input of a command?
Or, if it's not possible, how can I correctly use temporary files for such a task?
Passing a value to standard input in Bash is as simple as:
your-command <<< "$your_variable"
Always make sure you put quotes around variable expressions!
Be cautious, that this will probably work only in bash and will not work in sh.
Simple, but error-prone: using echo
Something as simple as this will do the trick:
echo "$blah" | my_cmd
Do note that this may not work correctly if $blah contains -n, -e, -E etc; or if it contains backslashes (bash's copy of echo preserves literal backslashes in absence of -e by default, but will treat them as escape sequences and replace them with corresponding characters even without -e if optional XSI extensions are enabled).
More sophisticated approach: using printf
printf '%s\n' "$blah" | my_cmd
This does not have the disadvantages listed above: all possible C strings (strings not containing NULs) are printed unchanged.
(cat <<END
$passwd
END
) | command
The cat is not really needed, but it helps to structure the code better and allows you to use more commands in parentheses as input to your command.
Note that the 'echo "$var" | command operations mean that standard input is limited to the line(s) echoed. If you also want the terminal to be connected, then you'll need to be fancier:
{ echo "$var"; cat - ; } | command
( echo "$var"; cat - ) | command
This means that the first line(s) will be the contents of $var but the rest will come from cat reading its standard input. If the command does not do anything too fancy (try to turn on command line editing, or run like vim does) then it will be fine. Otherwise, you need to get really fancy - I think expect or one of its derivatives is likely to be appropriate.
The command line notations are practically identical - but the second semi-colon is necessary with the braces whereas it is not with parentheses.
This robust and portable way has already appeared in comments. It should be a standalone answer.
printf '%s' "$var" | my_cmd
or
printf '%s\n' "$var" | my_cmd
Notes:
It's better than echo, reasons are here: Why is printf better than echo?
printf "$var" is wrong. The first argument is format where various sequences like %s or \n are interpreted. To pass the variable right, it must not be interpreted as format.
Usually variables don't contain trailing newlines. The former command (with %s) passes the variable as it is. However tools that work with text may ignore or complain about an incomplete line (see Why should text files end with a newline?). So you may want the latter command (with %s\n) which appends a newline character to the content of the variable. Non-obvious facts:
Here string in Bash (<<<"$var" my_cmd) does append a newline.
Any method that appends a newline results in non-empty stdin of my_cmd, even if the variable is empty or undefined.
I liked Martin's answer, but it has some problems depending on what is in the variable. This
your-command <<< """$your_variable"""
is better if you variable contains " or !.
As per Martin's answer, there is a Bash feature called Here Strings (which itself is a variant of the more widely supported Here Documents feature):
3.6.7 Here Strings
A variant of here documents, the format is:
<<< word
The word is expanded and supplied to the command on its standard
input.
Note that Here Strings would appear to be Bash-only, so, for improved portability, you'd probably be better off with the original Here Documents feature, as per PoltoS's answer:
( cat <<EOF
$variable
EOF
) | cmd
Or, a simpler variant of the above:
(cmd <<EOF
$variable
EOF
)
You can omit ( and ), unless you want to have this redirected further into other commands.
Try this:
echo "$variable" | command
If you came here from a duplicate, you are probably a beginner who tried to do something like
"$variable" >file
or
"$variable" | wc -l
where you obviously meant something like
echo "$variable" >file
echo "$variable" | wc -l
(Real beginners also forget the quotes; usually use quotes unless you have a specific reason to omit them, at least until you understand quoting.)

How to insert dynamic matching pattern in bash? [duplicate]

This question already has answers here:
Difference between single and double quotes in Bash
(7 answers)
Closed 3 years ago.
I was looking at this link Check if a Bash array contains a value which says how to check for existence of an item in a list as follows:
if printf '%s\n' ${myarray[#]} | grep -q -P '^mypattern$'; then
# ...
fi
However, I want mypattern value to be passed as a variable as follows:
mynewpattern="xyz"
then I was expecting the following to work
if printf '%s\n' ${myarray[#]} | grep -q -P '^"$mynewpattern"$'; then
# ...
fi
But it is not picking the new pattern of xyz. What is the appropriate syntax to insert the new pattern?
I have just started learning bash.
The single quotes are wrong; you want double quotes instead of single.
However, grep -P is also slightly wrong here; it's not properly portable, and your pattern doesn't use any of the syntax which -P enables; also, you should quote your array properly.
if printf '%s\n' "${myarray[#]}" |
grep -q "^$mypattern\$"
then
...
Text between single quotes is passed through verbatim. If you want the shell to perform variable interpolation, use double quotes (and then you need to escape any literal backslash, dollar sign, or backtick).
Could you please try using like grep -q -P "^$var$"(in your script)
Here is an example script for same scenario for an Input_file(since no samples for array elements were provided so explaining it with an sample/example script here).
##Shell variable
var="bla"
##A sample Input_file
cat << EOF > Input_file
blabla test test
123abcd123test
bla
EOF
##Following is the code to check.
if grep -q -P "^$var$" Input_file
then
echo "match found."
fi
Above will only match lines which are starting with variable val's value.

How do I take shell input literally? (i.e. keeping quotes etc. intact)

I am trying to write a bash script so that I will use to replace my egrep command. I want to be able to take the exact same input that is given to my script and feed it to egrep.
i.e.
#!/bin/bash
PARAMS=$#
`egrep "$PARAMS"`
But I have noticed that if I echo what I am executing, that the quotes have been removed as follows:
./customEgrep -nr "grep my ish" *
returns
egrep -nr grep my ish (file list from the expanded *)
Is there a way that I can take the input literally so I can use it directly with egrep?
You want this:
egrep "$#"
The quotes you type are not passed to the script; they're used to determine word boundaries. Using "$#" preserves those word boundaries, so egrep will get the same arguments as it would if you ran it directly. But you still won't see quotation marks if you echo the arguments.
" is a special char. you need to use escape character in order to retrieve "
use
./customEgrep -nr "\"grep my ish\"" *
If you don't need to do any parameter expansion in the argument, you can use
single quotes to avoid the need to escape the double quotes:
./customerEgrep -nr '"grep my ish"' *
$# is special when quoted. Try:
value=$( egrep "$#" )
It's not clear to me why you are using bacticks and ignoring the result, so I've used the $() syntax and assigned the value.
If for some reason you want to save the parameters to use later, you can also do things like:
for i; do args="$args '$i'"; done # Save the arguments
eval grep $args # Pass the arguments to grep without resetting $1,$2,...
eval set $args # Restore the arguments
grep "$#" # Use the restored arguments

Bash "-e" puzzler

I’m trying to build a command string based to pass in a “-e” flag and another variable into a another base script being call as a subroutine and have run into a strange problem; I’m losing the “-e” portion of the string when I pass it into the subroutine. I create a couple example which illustrate the issue, any help?
This works as you would expect:
$echo "-e $HOSTNAME"
-e ops-wfm
This does NOT; we lose the “-e” because it is interpreted as a special qualifier.
$myFlag="-e $HOSTNAME"; echo $myFlag
ops-wfm
Adding the “\” escape charactor doesn’t work either, I get the correct string with the "\" in front:
$myFlag="\-e $HOSTNAME"; echo $myFlag
\-e ops-wfm
How can I prevent -e being swallowed?
Use double-quotes:
$ myFlag="-e $HOSTNAME"; echo "${myFlag}"
-e myhost.local
I use ${var} rather than $var out of habit as it means that I can add characters after the variable without the shell interpreting them as part of the variable name.
echo may not be the best example here. Most Unix commands will accept -- to mark no more switches.
$ var='-e .bashrc' ; ls -l -- "${var}"
ls: -e .bashrc: No such file or directory
Well, you could put your variable in quotes:
echo "$myFlag"
...making it equivalent to your first example, which, as you say, works just fine.

Resources