This question already has answers here:
Why do backslashes disappear when run through echo?
(3 answers)
Closed 4 years ago.
Linux newbie here, but I have a script that is supposed to create a file:
VI_USERNAME=domain\\user
echo "VI_USERNAME=$VI_USERNAME" >> .visdkrc
File looks like this:
VI_USERNAME=domain user
How can I get my output to looks like this:
VI_USERNAME=domain\user
This does not happen with bash with the code you describe (protip: always test your own example):
$ cat myfile
VI_USERNAME=domain\\user
echo "VI_USERNAME=$VI_USERNAME" >> .visdkrc
$ bash myfile
$ cat .visdkrc
VI_USERNAME=domain\user
However, something similar happens with dash when the username starts with a "t":
$ cat myfile
VI_USERNAME=domain\\thatotherguy
echo "VI_USERNAME=$VI_USERNAME" >> .visdkrc
$ dash myfile
$ cat .visdkrc
VI_USERNAME=domain hatotherguy
(you may be using sh, which calls dash and not bash on Debian based distros since 2011)
The general rule about echo is that if you have to ask, use printf instead:
VI_USERNAME=domain\\user
printf '%s\n' "$VI_USERNAME" >> .visdkrc
echo is a legacy command that treats data differently across platforms and shells, especially with regard to flags and backslash sequences.
printf is well defined and has fewer pitfalls.
Related
This question already has answers here:
Capturing multiple line output into a Bash variable
(7 answers)
Closed 3 years ago.
I have a small script where I appended the output of linux mpstat to a log file.
#/bin/bash
CPU_USAGE=$(mpstat)
echo $CPU_USAGE >> temp.log
The problem is that the output of mpstat on the terminal is formatted properly in 3 lines like so
However, the output to the file is all in one line.
How do I format the output like the one on the terminal?
Just quote the variable so it is not seen as several different parameters to be printed one after the other:
echo "$CPU_USAGE" >> temp.log
You could just directly pipe the output to the file:
#!/bin/bash
mpstat >> temp.log
If you must store it in a variable, then quote it like:
#!/bin/bash
CPU_USAGE=$(mpstat)
echo "$CPU_USAGE" >> temp.log
Otherwise, bash will not interpret the newlines as part of the message to echo, but the whole output as a list of short strings to output.
This question already has answers here:
How do I use a variable argument number in a bash script?
(3 answers)
Closed 6 years ago.
What's going on everyone? I have this assignment in my Linux Operating System class and im having a little trouble. It asks me to,
Write a Bash shell script called chkread that takes an unlimited number of
arguments that all represent file names.
I have come up with this so far, but i don't think it's exactly what the professor is looking for.
~$ cat MY_SCRIPT
#!/bin/bash
echo ${unlimited arguments}
~$ bash MY_SCRIPT cat dog horse
cat dog horse
You could use something like this to handle multiple arguments in a bash script.
#!/bin/bash
file_names=("$#")
for name in "${file_names[#]}"; do
echo "$name"
done
And then when you call the script:
bash chkread.sh file1 file2 file3 file4
The script will print them to output:
file1
file2
file3
file4
But this is just an example. Inside the script you can do with them whatever you need to do.
Use $*. That will give you everything. For example:
#!/bin/bash
file_names=$*
echo $file_names
Output:
jbanks#efsappdev1:~$ x.sh `ls *.sql`
current.sql goop.sql latest.sql long.sql report.sql
jbanks#efsappdev1:~$ x.sh one two three
one two three
I'm trying to configure a file with a bash script. And the variables in the bash script are not written in file as it is written in script.
Ex:
#!/bin/bash
printf "%s" "template("$DATE\t$HOST\t$PRIORITY\t$MSG\n")" >> /file.txt
exit 0
This results to template('tttn') instead of template("$DATE\t$HOST\t$PRIORITY\t$MSG\n in file.
How do I write in the script so that the result is template("$DATE\t$HOST\t$PRIORITY\t$MSG\n in the configured file?
Is it possible to write variable as it looks in script to file?
Enclose the strings you want to write within single quotes to avoid variable replacement.
> FOO=bar
> echo "$FOO"
bar
> echo '$FOO'
$FOO
>
Using printf in any shell script is uncommon, just use echo with the -e option.
It allows you to use ANSI C metacharacters, like \t or \n. The \n at the end however isn't necessary, as echo will add one itself.
echo -e "template(${DATE}\t${HOST}\t${PRIORITY}\t${MSG})" >> file.txt
The problem with what you've written is, that ANSI C metacharacters, like \t can only be used in the first parameter to printf.
So it would have to be something like:
printf 'template(%s\t%s\t%s\t%s)\n' ${DATE} ${HOST} ${PRIORITY} ${MSG} >> file.txt
But I hope we both agree, that this is very hard on the eyes.
There are several escaping issues and the power of printf has not been used, try
printf 'template(%s\t%s\t%s\t%s)\n' "${DATE}" "${HOST}" "${PRIORITY}" "${MSG}" >> file.txt
Reasons for this separate answer:
The accepted answer does not fit the title of the question (see comment).
The post with the right answer
contains wrong claims about echo vs printf as of this post and
is not robust against whitespace in the values.
The edit queue is full at the moment.
This question already has answers here:
Passing arguments to an interactive program non-interactively
(5 answers)
Closed 7 years ago.
So suppose a normal command run in terminal goes like this....
user$ thecommand
Please enter your first name:
>
and then waits for your to type your name... straightforward, but if in a bash script I try and do something like:
#! /bin/bash
echo "What is your name?"
read name
thecommand
how would I have THE SCRIPT enter "$name" in response to "thecommand" instead of having the user manually input it themselves?
you can add input by pipe like this:
echo yourname | ./yourscript
for more inputs you can use printf
printf "input1\ninput2" | ./yourscript
where \n means new line and it will be used like new input.
Run your script like:
./yourscript.sh < file.txt
where file.txt will contain the name.
now your script will look for name from the file(file.txt), in file.txt you can type the names which will act as input for read command.
read command reads on line at a time so if u have more than on read command in your script you should have multiple lines in file.txt file
For complicated cases, for example if your input depends on the output of your command, you may write an "expect" script.
To see how it works you can auto-generate such script interactively
$ autoexpect thecommand
And then run it
$ expect -f script.exp
This question already has an answer here:
Bash: Confused by expanding asterisk
(1 answer)
Closed 7 years ago.
My problem can be reproduced with the following script:
#!/bin/bash
echo ".*" > foo.txt
echo $(cat foo.txt)
When I run this script I get a list of folders/files in my current directory:
$ ./test.sh
. .. .testfile
$ cat foo.txt
.*
My question is really a two parter:
1) Why does this happen?
2) Is there any way to get the literal string ".*" rather than a file list returned from $(cat [args])?
I originally ran into this problem working on a more complex script. Fixing this with an additional option passed into cat and/or alternative syntax would be ideal.
echo $(cat foo.txt)
Capturing cat's output and then echoing it right back out is not only redundant, it's error prone, as you've discovered. Just write:
cat foo.txt
Simpler, faster, it's the bees knees!
Or if you really, really want to capture it and then print it back out, use quotes. Quotes will prevent the .* from being interpreted as wildcards.
echo "$(cat foo.txt)"
There are still subtle problems with this command. If foo.txt contains -n, for instance, echo won't print -n, it'll print nothing. It turns out that echo simply isn't usable if you're the extra paranoid type. The super safe option is to eschew echo in favor of printf.
printf '%s\n' "$(cat foo.txt)"
This is as safe as one can get. It prints the contents of foo.txt and won't get tripped up by any special characters.
Although, you know, this is an awfully long winded way of writing:
cat foo.txt
Because the result returned by $() is un-quoted. It is equivalent to:
echo .*
which is subject to shell expansion.
You should double quote it:
echo "$(cat foo.txt)"
It will give correct output .*
Use More Quotes !
echo ".*" > foo.txt
echo "$(cat foo.txt)"
.*
The double quotes are mandatory, to avoid shell expansion:
Without the double quotes, all the characters are expanded from the shell, so the * becomes files in current directory