How to echo a new line which has < - echo

I want to echo a line
which has the following:
<ca>
-----BEGIN CERTIFICATE-----
MIIDyzCCAzSgAwIBAgIJAKRtpjsIvek1MA0GCSqGSIb3DQEBBQUAMIGgMQswCQYD
I tried
echo <^<ca>^>
but it didn't work.

You have three main options:
echo \<ca\> — escape special characters with backslash
echo '<ca>' — enclose string in single quotes
echo "<ca>" — enclose string in double quotes
If the line is stored in a variable, then only the third way (double quotes) works:
line="<ca>" # Could be written three ways
echo "$line" # The old-fashioned safe way (preserves spacing if there are spaces)
echo $line # The new-fashioned unsafe way, IMNSHO
The 'new-fashioned' way will be safe in that the angle brackets won't be interpreted as I/O redirections. It's unsafe in that it loses spacing. I strongly recommend using double quotes always; it will work*.
$ line="< aa bb cc >"
$ echo "$line"
< aa bb cc >
$
* Those who say the double quotes are unnecessary are referring to contexts like [[ ... ]] conditionals. I'd rather not deal with unnecessary special cases; using double quotes works correctly in that context too, so I don't spend the time remembering when I can safely omit double quotes — double quotes always work, so I always use them.

Try using single-quotes:
echo '<ca>'

This work out for me:
<?php
$str=htmlspecialchars("<ca>");
$str.="\n-----BEGIN CERTIFICATE-----\n";
$str.="MIIDyzCCAzSgAwIBAgIJAKRtpjsIvek1MA0GCSqGSIb3DQEBBQUAMIGgMQswCQYD\n";
echo nl2br($str);
?>
Are you trying to write to file or only display on screen?

You can simple use echo command for this. You can use it with single quotes or double quotes
echo "<ca>";

Related

sed not working as expected when trying to replace "user='mysql'" with "user=`whoami`"

The following command fails.
sed 's/user=\'mysql\'/user=`whoami`/g' input_file
An example input_file contains the following line
user='mysql'
The corresponding expected output is
user=`whoami`
(Yes, I literally want whoami between backticks, I don't want it to expand my userid.)
This should be what you need:
Using double quotes to enclose the sed command,
so that you are free to use single quotes in it;
escape backticks to avoid the expansion.
sed "s/user='mysql'/user=\`whoami\`/g" yourfile
I've intentionally omitted the -i option for the simple reason that it is not part of the issue.
To clarify the relation between single quotes and escaping, compare the following two commands
echo 'I didn\'t know'
echo 'I didn'\''t know'
The former will wait for further input as there's an open ', whereas the latter will work fine, as you are concatenating a single quoted string ('I didn'), an escaped single quote (\'), and another single quoted string ('t know').

sed: replace a pattern between two similar patterns, i.e. ( replace " to ' between two "," )

I have a csv file whose fields are delimited by double quote (") and comma (,), e.g:
"123","4"5""6","789"
However, there may be some double quote (") within the data, i.e. 4"5""6 which I need to transform into single quote ('), i.e.
I need to transform
"123","4"5""6","789"
to
"123","4'5''6","789"
I've tried something like
sed "s/\(\",\"\)\(\"\|[^\(","\)]\)*\(\",\"\)/\1'\3/"g
but (\"\|[^\(","\)]\)* only
match " OR not ","
but may be I need something like
match " AND not ","
Another approach may be perform sequential sed, i.e.
find and match 4"5""6 first
pass the result to next statement and replace to 4'5' '6
But for both ways, I don't know exactly how to do it.
Although I can replace all " into ' first and then re-format my csv but it seems to be costly, i.e.
sed -i -e "s/\"/'/g" -e "s/','/\",\"/g" -e "s/^'/\"/g" -e "s/'$/\"/g" myFile.csv
Try this:
$ sed ':a;s/\("[^,"]*\)"\([^,].*\)/\1'\''\2/;ta' <<< '"1"23","4"5""6","78"9"'
"1'23","4'5''6","78'9"
Opening double quote and following characters up to(but excluding) next closing " are captured and replaced with captured string and one single quote.
If replacement succeeds, ta loops to the beginning of the script for further replacements.
echo '"123","4"5""6","789"'|sed -r ':a;s/^([^,]+,"[^,]*)"([^"]*",)/\1\x27\2/;ta'
You may use the following awk approach:
echo '"123","4"5""6","789"' | awk -F, '{OFS=","; $2="\""gensub(/\042/, "\047","g", substr($2, 2, length($2)-2))"\"";}1'
The output:
"123","4'5''6","789"
Explanation:
-F, (OFS=",") - treating , as field separator
"\042" - double quote ASCII octal code
"\047" - single quote ASCII octal code
substr($2, 2, length($2)-2) - extracting substring from the second field except trailing double quotes, i.e. 4"5""6
gensub(/\042/, "\047","g", [target]) - substitutes all double quotes with single quotes within the target string
Another awk proposal:
echo '"123","4"5""6","789"' |awk '{sub(/4"5""/,"4\47"5"\47\47")}1'
"123","4'5''6","789"
find and match 4"5""6 first
pass the result to next statement and replace to 4'5' '6
This is possible in perl
$ echo '"123","4"5""6","789"' | perl -pe 's/"\K[^,]+(?=")/$&=~s|"|\x27|gr/ge'
"123","4'5''6","789"
"\K[^,]+(?=") match column content, leave out outer double quotes with use of lookarounds
$&=~s|"|\x27|gr replace the double quotes found within column content with single quotes
The e modifier used allows this usage of Perl code instead of replacement string
Workaround with sed, involves messy branches
$ echo '"123","4"5""6","789"' | sed -E ':a s/("[^,]+)"([^,]+")(,|$)/\1\x27\2\3/; ta'
"123","4'5''6","789"
:a mark label
("[^,]+)"([^,]+")(,|$) matches column content with at least one inner double quote
\1\x27\2\3 replace the inner double quote with single quote
ta branch to label a as long as there is a match

Using variables within sed

I am trying to use a variable within sed but cant work it out. I have tried
read -p " enter your name" name
sed -i 's/myname/$name/g' file
But unfortunately it just replaces myname with "$name".
Is there an alternative way?
The problem is that the bash shell does not do variable expansion within single quotes. For example:
pax> name=paxdiablo
pax> echo 'Hello, $name, how are you?'
Hello, $name, how are you?
For simple cases like this, you can just use double quotes:
pax> echo "Hello, $name, how are you?"
Hello, paxdiablo, how are you?
Having said that, there are some serious concerns with just using arbitrary data expanded like this. A clever attacker could give a name containing characters that would cause your sed to do things you may not want (via an injection attack):
pax#paxbox$ name='/; e printenv; echo '
pax#paxbox$ echo 'Hello, myname' | sed "s/myname/$name/"
LESSOPEN=| /usr/bin/lesspipe %s
USER=pax
: (lots of other stuff about my environment I don't want people to see)
HOSTTYPE=x86_64
/
Hello,
And it doesn't even have to be clever - anyone entering a name containing / will almost certainly cause your sed to fail.
You should either sanitise your input data or use tools where the scope for attack is greatly reduced.

echo/append a string with multiple double quotes

I'm processing a text file reading line by line and massaging/filtering the data before writing to another file. Some lines in the original file contain multiple double quotes, others don't:
Dummy line 'from' a file with ""multiple double"" """quotes""" and single double "quotes".
I want to preserve all those weird quotes, basically treat the whole line as raw data. However, currently my approach removes all instances of double quotes
while read -r line
do
# do some filtering
echo "$line">> $ebooks ;;
done < $filename
I assume sed can help with that, but it seems that even if I insert sed substitution after echo "$line", echo would already have already removed all quotes. How to apply sed without echo or what is a good approach for such issues?
Please, POSIX compliant only (sh) solutions, no bash/zsh/csh/etc.

How can I have a newline in a string in sh?

This
STR="Hello\nWorld"
echo $STR
produces as output
Hello\nWorld
instead of
Hello
World
What should I do to have a newline in a string?
Note: This question is not about echo.
I'm aware of echo -e, but I'm looking for a solution that allows passing a string (which includes a newline) as an argument to other commands that do not have a similar option to interpret \n's as newlines.
If you're using Bash, you can use backslash-escapes inside of a specially-quoted $'string'. For example, adding \n:
STR=$'Hello\nWorld'
echo "$STR" # quotes are required here!
Prints:
Hello
World
If you're using pretty much any other shell, just insert the newline as-is in the string:
STR='Hello
World'
Bash recognizes a number of other backslash escape sequences in the $'' string. Here is an excerpt from the Bash manual page:
Words of the form $'string' are treated specially. The word expands to
string, with backslash-escaped characters replaced as specified by the
ANSI C standard. Backslash escape sequences, if present, are decoded
as follows:
\a alert (bell)
\b backspace
\e
\E an escape character
\f form feed
\n new line
\r carriage return
\t horizontal tab
\v vertical tab
\\ backslash
\' single quote
\" double quote
\nnn the eight-bit character whose value is the octal value
nnn (one to three digits)
\xHH the eight-bit character whose value is the hexadecimal
value HH (one or two hex digits)
\cx a control-x character
The expanded result is single-quoted, as if the dollar sign had not
been present.
A double-quoted string preceded by a dollar sign ($"string") will cause
the string to be translated according to the current locale. If the
current locale is C or POSIX, the dollar sign is ignored. If the
string is translated and replaced, the replacement is double-quoted.
Echo is so nineties and so fraught with perils that its use should result in core dumps no less than 4GB. Seriously, echo's problems were the reason why the Unix Standardization process finally invented the printf utility, doing away with all the problems.
So to get a newline in a string, there are two ways:
# 1) Literal newline in an assignment.
FOO="hello
world"
# 2) Command substitution.
BAR=$(printf "hello\nworld\n") # Alternative; note: final newline is deleted
printf '<%s>\n' "$FOO"
printf '<%s>\n' "$BAR"
There! No SYSV vs BSD echo madness, everything gets neatly printed and fully portable support for C escape sequences. Everybody please use printf now for all your output needs and never look back.
What I did based on the other answers was
NEWLINE=$'\n'
my_var="__between eggs and bacon__"
echo "spam${NEWLINE}eggs${my_var}bacon${NEWLINE}knight"
# which outputs:
spam
eggs__between eggs and bacon__bacon
knight
I find the -e flag elegant and straight forward
bash$ STR="Hello\nWorld"
bash$ echo -e $STR
Hello
World
If the string is the output of another command, I just use quotes
indexes_diff=$(git diff index.yaml)
echo "$indexes_diff"
The problem isn't with the shell. The problem is actually with the echo command itself, and the lack of double quotes around the variable interpolation. You can try using echo -e but that isn't supported on all platforms, and one of the reasons printf is now recommended for portability.
You can also try and insert the newline directly into your shell script (if a script is what you're writing) so it looks like...
#!/bin/sh
echo "Hello
World"
#EOF
or equivalently
#!/bin/sh
string="Hello
World"
echo "$string" # note double quotes!
The only simple alternative is to actually type a new line in the variable:
$ STR='new
line'
$ printf '%s' "$STR"
new
line
Yes, that means writing Enter where needed in the code.
There are several equivalents to a new line character.
\n ### A common way to represent a new line character.
\012 ### Octal value of a new line character.
\x0A ### Hexadecimal value of a new line character.
But all those require "an interpretation" by some tool (POSIX printf):
echo -e "new\nline" ### on POSIX echo, `-e` is not required.
printf 'new\nline' ### Understood by POSIX printf.
printf 'new\012line' ### Valid in POSIX printf.
printf 'new\x0Aline'
printf '%b' 'new\0012line' ### Valid in POSIX printf.
And therefore, the tool is required to build a string with a new-line:
$ STR="$(printf 'new\nline')"
$ printf '%s' "$STR"
new
line
In some shells, the sequence $' is a special shell expansion.
Known to work in ksh93, bash and zsh:
$ STR=$'new\nline'
Of course, more complex solutions are also possible:
$ echo '6e65770a6c696e650a' | xxd -p -r
new
line
Or
$ echo "new line" | sed 's/ \+/\n/g'
new
line
A $ right before single quotation marks '...\n...' as follows, however double quotation marks doesn't work.
$ echo $'Hello\nWorld'
Hello
World
$ echo $"Hello\nWorld"
Hello\nWorld
Disclaimer: I first wrote this and then stumbled upon this question. I thought this solution wasn't yet posted, and saw that tlwhitec did post a similar answer. Still I'm posting this because I hope it's a useful and thorough explanation.
Short answer:
This seems quite a portable solution, as it works on quite some shells (see comment).
This way you can get a real newline into a variable.
The benefit of this solution is that you don't have to use newlines in your source code, so you can indent
your code any way you want, and the solution still works. This makes it robust. It's also portable.
# Robust way to put a real newline in a variable (bash, dash, ksh, zsh; indentation-resistant).
nl="$(printf '\nq')"
nl=${nl%q}
Longer answer:
Explanation of the above solution:
The newline would normally be lost due to command substitution, but to prevent that, we add a 'q' and remove it afterwards. (The reason for the double quotes is explained further below.)
We can prove that the variable contains an actual newline character (0x0A):
printf '%s' "$nl" | hexdump -C
00000000 0a |.|
00000001
(Note that the '%s' was needed, otherwise printf will translate a literal '\n' string into an actual 0x0A character, meaning we would prove nothing.)
Of course, instead of the solution proposed in this answer, one could use this as well (but...):
nl='
'
... but that's less robust and can be easily damaged by accidentally indenting the code, or by forgetting to outdent it afterwards, which makes it inconvenient to use in (indented) functions, whereas the earlier solution is robust.
Now, as for the double quotes:
The reason for the double quotes " surrounding the command substitution as in nl="$(printf '\nq')" is that you can then even prefix the variable assignment with the local keyword or builtin (such as in functions), and it will still work on all shells, whereas otherwise the dash shell would have trouble, in the sense that dash would otherwise lose the 'q' and you'd end up with an empty 'nl' variable (again, due to command substitution).
That issue is better illustrated with another example:
dash_trouble_example() {
e=$(echo hello world) # Not using 'local'.
echo "$e" # Fine. Outputs 'hello world' in all shells.
local e=$(echo hello world) # But now, when using 'local' without double quotes ...:
echo "$e" # ... oops, outputs just 'hello' in dash,
# ... but 'hello world' in bash and zsh.
local f="$(echo hello world)" # Finally, using 'local' and surrounding with double quotes.
echo "$f" # Solved. Outputs 'hello world' in dash, zsh, and bash.
# So back to our newline example, if we want to use 'local', we need
# double quotes to surround the command substitution:
# (If we didn't use double quotes here, then in dash the 'nl' variable
# would be empty.)
local nl="$(printf '\nq')"
nl=${nl%q}
}
Practical example of the above solution:
# Parsing lines in a for loop by setting IFS to a real newline character:
nl="$(printf '\nq')"
nl=${nl%q}
IFS=$nl
for i in $(printf '%b' 'this is line 1\nthis is line 2'); do
echo "i=$i"
done
# Desired output:
# i=this is line 1
# i=this is line 2
# Exercise:
# Try running this example without the IFS=$nl assignment, and predict the outcome.
I'm no bash expert, but this one worked for me:
STR1="Hello"
STR2="World"
NEWSTR=$(cat << EOF
$STR1
$STR2
EOF
)
echo "$NEWSTR"
I found this easier to formatting the texts.
Those picky ones that need just the newline and despise the multiline code that breaks indentation, could do:
IFS="$(printf '\nx')"
IFS="${IFS%x}"
Bash (and likely other shells) gobble all the trailing newlines after command substitution, so you need to end the printf string with a non-newline character and delete it afterwards. This can also easily become a oneliner.
IFS="$(printf '\nx')" IFS="${IFS%x}"
I know this is two actions instead of one, but my indentation and portability OCD is at peace now :) I originally developed this to be able to split newline-only separated output and I ended up using a modification that uses \r as the terminating character. That makes the newline splitting work even for the dos output ending with \r\n.
IFS="$(printf '\n\r')"
On my system (Ubuntu 17.10) your example just works as desired, both when typed from the command line (into sh) and when executed as a sh script:
[bash]§ sh
$ STR="Hello\nWorld"
$ echo $STR
Hello
World
$ exit
[bash]§ echo "STR=\"Hello\nWorld\"
> echo \$STR" > test-str.sh
[bash]§ cat test-str.sh
STR="Hello\nWorld"
echo $STR
[bash]§ sh test-str.sh
Hello
World
I guess this answers your question: it just works. (I have not tried to figure out details such as at what moment exactly the substitution of the newline character for \n happens in sh).
However, i noticed that this same script would behave differently when executed with bash and would print out Hello\nWorld instead:
[bash]§ bash test-str.sh
Hello\nWorld
I've managed to get the desired output with bash as follows:
[bash]§ STR="Hello
> World"
[bash]§ echo "$STR"
Note the double quotes around $STR. This behaves identically if saved and run as a bash script.
The following also gives the desired output:
[bash]§ echo "Hello
> World"
I wasn't really happy with any of the options here. This is what worked for me.
str=$(printf "%s" "first line")
str=$(printf "$str\n%s" "another line")
str=$(printf "$str\n%s" "and another line")
This isn't ideal, but I had written a lot of code and defined strings in a way similar to the method used in the question. The accepted solution required me to refactor a lot of the code so instead, I replaced every \n with "$'\n'" and this worked for me.