How to add double quotation marks ("") around pipe-separated fields [duplicate] - bash

This question already has answers here:
How can I add quotation marks to fields in a CSV file?
(4 answers)
Closed 2 years ago.
The community reviewed whether to reopen this question 1 year ago and left it closed:
Original close reason(s) were not resolved
Let's say I have a file with this structure:
1|2|3|4|
5|6|7|8|
9|10|11|12|
However, I want my file to look like this (expected output):
"1"|"2"|"3"|"4"|
"5"|"6"|"7"|"8"|
"9"|"10"|"11"|"12"|
I am trying to used sed command in the following way:
sed 's/^/"/g'
Unfortunately, it only adds quotation marks at the beginning of each line:
"1|2|3|4|
"5|6|7|8|
"9|10|11|12|

^ means "the beginning of a line". Use [^|] instead which means "anything but |". If your implementation of sed supports +, you can use
sed -E 's/[^|]+/"&"/g'
otherwise, you need to be more verbose
sed 's/[^|][^|]*/"&"/g'
& represents the matched part.

You can use
sed -E 's/[^|]+/"&"/g' file > newfile
The -E option enables the POSIX ERE syntax and [^|]+ thus matches one or more chars other than |, and "&" replaces each with its copy enclosed with " on both sides.
See the online sed demo:
s='1|2|3|4|
5|6|7|8|
9|10|11|12|'
sed -E 's/[^|]+/"&"/g' <<< "$s"
Output:
"1"|"2"|"3"|"4"|
"5"|"6"|"7"|"8"|
"9"|"10"|"11"|"12"|

Here is a gnu awk way of doing the same:
awk -v RS="[|\n]+" '{ORS=RT; print "\"" $0 "\""}' file
"1"|"2"|"3"|"4"|
"5"|"6"|"7"|"8"|
"9"|"10"|"11"|"12"|

Related

Append text to top of file using sed doesn't work for variable whose content has "/" [duplicate]

This question already has answers here:
Using different delimiters in sed commands and range addresses
(3 answers)
Closed 1 year ago.
I have a Visual Studio project, which is developed locally. Code files have to be deployed to a remote server. The only problem is the URLs they contain, which are hard-coded.
The project contains URLs such as ?page=one. For the link to be valid on the server, it must be /page/one .
I've decided to replace all URLs in my code files with sed before deployment, but I'm stuck on slashes.
I know this is not a pretty solution, but it's simple and would save me a lot of time. The total number of strings I have to replace is fewer than 10. A total number of files which have to be checked is ~30.
An example describing my situation is below:
The command I'm using:
sed -f replace.txt < a.txt > b.txt
replace.txt which contains all the strings:
s/?page=one&/pageone/g
s/?page=two&/pagetwo/g
s/?page=three&/pagethree/g
a.txt:
?page=one&
?page=two&
?page=three&
Content of b.txt after I run my sed command:
pageone
pagetwo
pagethree
What I want b.txt to contain:
/page/one
/page/two
/page/three
The easiest way would be to use a different delimiter in your search/replace lines, e.g.:
s:?page=one&:pageone:g
You can use any character as a delimiter that's not part of either string. Or, you could escape it with a backslash:
s/\//foo/
Which would replace / with foo. You'd want to use the escaped backslash in cases where you don't know what characters might occur in the replacement strings (if they are shell variables, for example).
The s command can use any character as a delimiter; whatever character comes after the s is used. I was brought up to use a #. Like so:
s#?page=one&#/page/one#g
A very useful but lesser-known fact about sed is that the familiar s/foo/bar/ command can use any punctuation, not only slashes. A common alternative is s#foo#bar#, from which it becomes obvious how to solve your problem.
add \ before special characters:
s/\?page=one&/page\/one\//g
etc.
In a system I am developing, the string to be replaced by sed is input text from a user which is stored in a variable and passed to sed.
As noted earlier on this post, if the string contained within the sed command block contains the actual delimiter used by sed - then sed terminates on syntax error. Consider the following example:
This works:
$ VALUE=12345
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
MyVar=12345
This breaks:
$ VALUE=12345/6
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
sed: -e expression #1, char 21: unknown option to `s'
Replacing the default delimiter is not a robust solution in my case as I did not want to limit the user from entering specific characters used by sed as the delimiter (e.g. "/").
However, escaping any occurrences of the delimiter in the input string would solve the problem.
Consider the below solution of systematically escaping the delimiter character in the input string before having it parsed by sed.
Such escaping can be implemented as a replacement using sed itself, this replacement is safe even if the input string contains the delimiter - this is since the input string is not part of the sed command block:
$ VALUE=$(echo ${VALUE} | sed -e "s#/#\\\/#g")
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
MyVar=12345/6
I have converted this to a function to be used by various scripts:
escapeForwardSlashes() {
# Validate parameters
if [ -z "$1" ]
then
echo -e "Error - no parameter specified!"
return 1
fi
# Perform replacement
echo ${1} | sed -e "s#/#\\\/#g"
return 0
}
this line should work for your 3 examples:
sed -r 's#\?(page)=([^&]*)&#/\1/\2#g' a.txt
I used -r to save some escaping .
the line should be generic for your one, two three case. you don't have to do the sub 3 times
test with your example (a.txt):
kent$ echo "?page=one&
?page=two&
?page=three&"|sed -r 's#\?(page)=([^&]*)&#/\1/\2#g'
/page/one
/page/two
/page/three
replace.txt should be
s/?page=/\/page\//g
s/&//g
please see this article
http://netjunky.net/sed-replace-path-with-slash-separators/
Just using | instead of /
Great answer from Anonymous. \ solved my problem when I tried to escape quotes in HTML strings.
So if you use sed to return some HTML templates (on a server), use double backslash instead of single:
var htmlTemplate = "<div style=\\"color:green;\\"></div>";
A simplier alternative is using AWK as on this answer:
awk '$0="prefix"$0' file > new_file
You may use an alternative regex delimiter as a search pattern by backs lashing it:
sed '\,{some_path},d'
For the s command:
sed 's,{some_path},{other_path},'

sed -i ‘’ -e '/javaagent.jar/ s/$/ proxyPort=8080/' this command should append string only if the line is uncommented [duplicate]

This question already has answers here:
sed - Commenting a line matching a specific string AND that is not already commented out
(10 answers)
sed in-place flag that works both on Mac (BSD) and Linux
(15 answers)
Ignore comments (#) using sed, but keep the lines untouched
(5 answers)
Closed 2 years ago.
Im using below to append proxyport=8080 to the end of the line where javaagent.jar string found and below is working fine, but this should ignore if there is a # (commented line) in the text file
sed -i '' -e '/javaagent.jar/ s/$/ proxyPort=8080/'
Example input:
#/opt/ver/inmind/javaagent.jar
/opt/ver/inmind/javaagent.jar
Example output should be:
#/opt/ver/inmind/javaagent.jar
/opt/ver/inmind/javaagent.jar proxyPort=8080
Assuming you have a FreeBSD sed version (as you have -i '' in your command), you can use
sed -i '' -e '/^#/!s/javaagent\.jar.*/& proxyPort=8080/' file
See the online demo.
The /^#/! part stops processing lines starting with # (add [[:space:]]* after ^ to account for indentation, any leading whitespace), and if there is no # at the start, s/javaagent\.jar.*/& proxyPort=8080/ finds javaagent.jar + the rest of the line and replaces this match with itself (with &) and adds a space and proxyPort=8080.

How do I remove a line that does not contain a specific character? [duplicate]

This question already has answers here:
In-place edits with sed on OS X
(8 answers)
Closed 2 years ago.
For example, I want do remove all lines in a textile that do not contain the character '#'
I have already tried to use sed like so
sed '/#/!d' data.txt
What am I missing? Shouldn't this work?
I prefer using ed over the non-standard sed -i, especially if it needs to be portable:
printf "%s\n" "v/#/d" w | ed -s filename
This deletes every line that doesn't contain a #, and saves the changed file back to disc.
sed -n '/#/p' [file]
-n suppress default printing
/#/ match on # anywhere on the line
p print if it matches
Add -i for in-place editing of the file (if supplied).

Use sed with variable that contains dot [duplicate]

This question already has answers here:
Search and replace with sed when dots and underscores are present
(5 answers)
Closed 6 years ago.
I am trying to replace (for instance) 6.0 by 6.1 in a file, without 640 being replaced by 6.1
I have currently:
sed -i "s/$previousName/$newName/" 'myFile'
I think that the solution could be in here, but I don't find the right solution.
EDIT both string are inside a variable and the question this is supposed to be a duplicate of doesn't treat this case
Using an inner sed:
sed -i "s#$(echo $previousName | sed 's/\./\\./g')#$newName#g" myFile
Try this:
sed -i "s/6\.0/6.1/" 'myFile'
The key is to escape the . character in the pattern which has special meaning. By default it matches any character (including 0 in 640), whereas with a \ in front of it, it only matches a literal ..
Since you have the pattern in a variable, you could escape the . in it first like this:
previousNameE="$(sed -e 's/\./\\./' <<< "$previousName")"
sed -i "s/$previousNameE/$newName/" 'myFile'
if perl is acceptable:
perl -i -pe "s/\Q$previousName/$newName/" 'myFile'
From perldoc for \Q
Returns the value of EXPR with all the ASCII non-"word" characters
backslashed. (That is, all ASCII characters not matching
/[A-Za-z_0-9]/ will be preceded by a backslash in the returned string,
regardless of any locale settings.) This is the internal function
implementing the \Q escape in double-quoted strings
Another example:
$ echo '*.^[}' | perl -pe 's/\Q*.^[}/q($abc$)/e'
$abc$
Further reading: Perl flags -pe, -pi, -p, -w, -d, -i, -t?

using sed to write a shell script [duplicate]

This question already has answers here:
shell scripting using sed
(3 answers)
Closed 9 years ago.
So, I want to read file from stdin, delete all '/' in line that contain exactly 3 '/', and write the output to stdout. So a file contain:
/a1/b/c
/a/b2
///
/a
will have output:
a1bc
/a/b2
/a
I am thinking something like this:
sed -r 's/\/[^\/]*\/[^\/]*\/.*/"I not sure what do I need to put in here"/g'
however, I am not really sure what do I need to put in the replace session.
A sed solution:
sed '/.*\/.*\/.*\//{s#/##g}' file
If Perl is ok for you:
perl -F/ -ape '$_=#F>3?join"",#F:join "/",#F;' file
sed -e '/^[^\/]*\/[^\/]*\/[^\/]*\/[^\/]*$/ s%/%%g'
The gruesome pattern looks for start of line, a sequence of zero or more non-slashes followed by a slash, more non-slashes and a second slash, more non-slashes and a third slash, more non-slashes and the end of line. On any line that matches that, substitute the slashes by nothing globally.
There are other ways to write the regex, but they aren't substantially clearer. This will work in pretty much any version of sed. So will this:
sed -e '/^\([^\/]*\/\)\{3\}[^\/]*$/ s%/%%g'
It looks for start of line, 3 units of (zero or more non-slashes followed by a slash), zero or more non-slashes and end of line.
If your sed has extended regular expressions (GNU sed, for example), then you can gain some notational convenience.
sed -r -e '/^([^\/]*\/){3}[^\/]*$/ s%/%%g'
sed -r -e 's%^([^/]*)/([^/]*)/([^/]*)/([^/]*)$%\1\2\3\4%'
The latter captures the four sets of 'zero or more non-slashes' and pastes them together to make the replacement. You could write that with the non-extended regular expressions, but it would be even more laden with backslashes than before.
This is much simpler in awk:
awk -F/ 'NF==4 { gsub("/","") } {print}' tmp.txt

Resources