Swap two characters in bash with tr or similar - bash

I'm doing a bash script and I have a problem. I would like to change the position of two characters in a string.
My input is the following:
"aaaaa_eeeee"
The desired output is:
"eeeee_aaaaa"
I don't want to invert the string or anything else like that, what I need is to replace the character "a" by the "e" and the "e" by the "a". I have tried to make a echo "aaaaa_eeeee" | tr "a" "e . The first replacement is simple but the second one I don't know how to do it.

You can give multiple original and replacement characters to tr. Each character in the original string is replaced with the corresponding replacement character.
echo "aaaaa_eeeee" | tr "ae" "ea"

Pass Translation Sets as Arguments
To make the substitutions work in a single logical pass, you need to pass multiple characters to the tr utility. The man page for the BSD version of tr describes the use of translation sets as follows:
[T]he characters in string1 are translated into the characters in string2 where the first character in string1 is translated into the first character in string2 and so on. If string1 is longer than string2, the last character found in string2 is duplicated until string1 is exhausted.
For example:
$ tr "ae" "ea" <<< "aaaaa_eeeee"
eeeee_aaaaa
This maps a => e and e => a in a single logical pass, avoiding the issues that would result in trying to map the replacements sequentially.

This is a job for rev:
echo "aaaaa_eeeee"|rev
eeeee_aaaaa

Related

BASH - Capture string between a FIXED and 2 possible variables

To get what is between "aa=" and either % or empty
string = "aa=value%bb"
string2 = "bb=%aa=value"
The rule must work on both strings to get the value of "aa="
I would like a BASH LANGUAGE solution if possible.
Use this:
result=$(echo "$string" | grep -o 'aa=[^%]*')
result=${result:3} # remove aa=
[^%]* matches any sequence of characters that doesn't contain %, so it will stop when it gets to % or the end of the string. $(result:3} expands to the substring starting from character 3, which removes aa= from the beginning.

how to replace special characters in bash

I have two problems. I have an input like this
foo.o
bar.o
I need to replace the dot with a character of my choice (in this case it is "D") and I need to append "] at the end of each line.
I know how to append ] with awk
awk '{print $0"]"}'
but I dont know how to add " as well, my simple attempt was
awk '{print $0""]"}'
but as expected that doesnt work.
Also I don't know how to replace the dot at all.
Thanks for your help.
. is a regex metacharacter. Put it within a character class:
awk '{gsub("[.]", "D", $0)}{print $0"]"}'
or double escape it:
awk '{gsub("\\.", "D", $0)}{print $0"]"}'
For adding the quote, escape it. In order to add, "], say:
print $0"\"]"
With sed:
$ sed 'y/./D/;s/$/]/' input.txt
fooDo]
barDo]
$
y/./D/ replaces all instances of "." with "D". The y command is a simple string replacement and not a regexp replacement, so the . doesn't need any special escaping in this command.
s/$/]/ matches the end of the line and effectively appends "]".

Difference of answers while using split function in Ruby

Given the following inputs:
line1 = "Hey | Hello | Good | Morning"
line2 = "Hey , Hello , Good , Morning"
file1=length1=name1=title1=nil
Using ',' to split the string as follows:
file1, length1, name1, title1 = line2.split(/,\s*/)
I get the following output:
puts file1,length1,name1,title1
>Hey
>Hello
>Good
>Morning
However, using '|' to split the string I receive a different output:
file1, length1, name1, title1 = line2.split(/|\s*/)
puts file1,length1,name1,title1
>H
>e
>y
Both the strings are same except the separating symbol (a comma in first case and a pipe in second case). The format of the split function I am using is also the same except, of course, for the delimiting character. What causes this variation?
The problem is because | has the meaning of OR in regex. If you want literal character, then you need to escape it \|. So the correct regex should be /\|\s*/
Currently, the regex /|\s*/ means empty string or series of whitespace character. Since the empty string specified first in the OR, the regex engine will break the string up at every character (you can imagine that there is an empty string between characters). If you swap it to /\s*|/, then the whitespaces will be preferred over empty string where possible and there will be no white spaces in the list of tokens after splitting.

Converting a "A B [C] D" formatted file to a CSV file

I have a file which has contents on every line following this format (A, B, C, and D represent text):
A B [C] D
E.g.:
cat Cat [noun] This animal likes to eat mice.
The first separator is the first occurrence of a space (" ") on a line.
The second separator is the first occurrence of a space followed by a square opening bracket (" [").
The final separator is the first occurrence of a square closing bracket followed by a space ("] ").
I want to convert all of the content in this file to a CSV file, where # is used in place of commas:
A#B#C#D
The original file contains many foreign characters in UTF-8.
There are no spaces or brackets within the contents of A and B.
C sometimes contains spaces, but no brackets inside the two given.
D contains anything from spaces, square brackets, etc. and the contents should remain unchanged by the conversion.
How can I convert this file to that format?
Sounds like a task for regular expressions. The literal brackets make this a bit ugly, but here's one that matches your example text.
^([^ ]+) ([^ ]+) \[([^]]+)\] (.*)$
You'll have to check the regular expression api of whatever language you're writing your code in. For help in creating regexes, I recommend Expresso: http://www.ultrapico.com/Expresso.htm
You need to perform char substitution. I suggest you use sed with regular expression. This is a piece of code corresponding to your example:
sed -r 's/( |\[|\])+/#/g' file_to_modify.txt > file_for_output.txt
For substituting every column in a specific way, the following form is used:
sed -r 's/([^ ]+) ([^ ]+) \[([^]]+)] (.*$)/\1#\2#\3#\4/g' f1.txt > f2.txt
The string looks like a user-defined csv fomart.
Maybe you can try csv module in python:
$ python3
>>> import csv, io, re
>>> '#'.join(next(csv.reader(io.StringIO(re.sub('[\[\]]', '\034', 'A B [c c c] D')), delimiter=' ', quotechar='\034')))
'A#B#c c c#D'

pattern matching in ruby

cud any body tell me how this expression works
output = "#{output.gsub(/grep .*$/,'')}"
before that opearation value of ouptput is
"df -h | grep /mnt/nand\r\n/dev/mtdblock4 248.5M 130.7M 117.8M 53% /mnt/nand\r\n"
but after opeartion it comes
"df -h | \n/dev/mtdblock4 248.5M 248.5M 130.7M 117.8M 53% /mnt/nand\r\n "
plzz help me
Your expression is equivalent to:
output.gsub!(/grep .*$/,'')
which is much easier to read.
The . in the regular expression matches all characters except newline by default. So, in the string provided, it matches "grep /mnt/nand", and will substitute a blank string for that. The result is the provided string, without the matched substring.
Here is a simpler example:
"hello\n\n\nworld".gsub(/hello.*$/,'') => "\n\n\nworld"
In both your provided regex, and the example above, the $ is not necessary. It is used as an anchor to match the end of a line, but since the pattern immediately before it (.*) matches everything up to a newline, it is redundant (but does not cause harm).
Since gsub returns a string, your first line is exactly the same as
output = output.gsub(/grep .*$/, '')
which takes the string and removes any occurance of the regexp pattern
/grep .*$/
i.e. all parts of the string that start with 'grep ' until the end of the string or a line break.
There's a good regexp tester/reference here. This one matches the word "grep", then a space, then any number of characters until the next line-break (\r or \n). "." by itself means any character, and ".*" together means any number of them, as many as possible. "$" means the end of a line.
For the '$', see here http://www.regular-expressions.info/reference.html
".*$" means "take every character from the end of the string" ; but the parser will interpret the "\n" as the end of a line, so it stops here.

Resources