How to print nth line by replacing cut with sed - shell

I have to write a function taking as argument a csv file named players.csv and a number giving the line to print.
Indded, i have to print the nth line 2column and 3rd column with a "is" between. For example Mike is John. column delimeter is ";".
I have the following code which is working :
sed -n "$2p" players.csv | cut -d ";" -f 2,3 --output-delimiter=' is '
However, I have to do the same without using cut. I can only use sed and wc. Do you have any idea what sed command I can use to have the same behavior as with cut.
Thank you for your attention and your help.

You were almost there:
sed -En "$2"'s/[^;]*;([^;]*);([^;]*).*/\1 is \2/p' players.csv

Related

Awk/sed replace in each line with previous string in the line

I have a file test.txt like this (but containing many more lines)
/foo/bar/how hello
/foo/bar/are hello
/foo/bar/you hello
I want to get this output:
/foo/bar/how how
/foo/bar/are are
/foo/bar/you you
I have tried this:
while read line
do
bla=$(echo $line | cut -f4 -d"/" | cut -f1 -d" ")
sed -i "s/hello/$bla/"
done <test.txt
But the output is:
sed: no input files
sed: no input files
sed: no input files
When I provide the filename (while read line; do bla=$(echo $line | cut -f4 -d"/" | cut -f1 -d" "); sed -i "s/hello/$bla/" test.txt ; done <test.txt), I get this:
/foo/bar/how how
/foo/bar/are how
/foo/bar/you how
I would like to replace on each line some constant pattern by a pattern appearing before on the same line and that changes from line to line. Any idea on how I could do that (using sed or awk)? Many thanks!
$ sed 's~\([^/]*\) .*~\1 \1~' file
/foo/bar/how how
/foo/bar/are are
/foo/bar/you you
Below awk solution might help
awk '{$2=$1;sub(/.*\//,"",$2)}1' test.txt
Ouput
/foo/bar/how how
/foo/bar/are are
/foo/bar/you you
Notes
By default awk fields are whitespace separated so, you have two fields ie $1 and $2.
First assign the first field of every record to second ie $2=$1
Then, in the second field, strip the the part till the last / using sub(/.*\//,"",$2).
1 at the end is the simplest of awk command which prints each record.
Try this:
$ sed 's~\(.*/\)\([^ ]*\) .*~\1\2 \2~' test.txt
/foo/bar/how how
/foo/bar/are are
/foo/bar/you you
Use the -i option to edit the file in place:
sed -i 's~\(.*/\)\([^ ]*\) .*~\1\2 \2~' test.txt
Explanation:
s: substitute
\(.*/\)\: any character up to last /
followed by \([^ ]*\): any non-space character followed by a space
Using backreference, the strings that matches the pattern are replaced with : first group (/foo/bar/) followed by repeated second group (the word after last / : how, are or you).

Trim Line After Third Occurence of Colon

I am parsing through a log file and I am trying to clean up the output.
Here's a sample input line
2016-04-11 12:45:26 : TEXT TO REMOVE
Here's my current code which removes everything after the first colon.
sed 's/:.*//'
which outputs
2016-04-11 12
I'd like to modify this so that it removes everything after the third colon instead (so I end up with just the date and time).
Here's a sample output I would like:
2016-04-11 12:45:26
That's what cut was invented to do:
$ cut -d':' -f1-3 file
2016-04-11 12:45:26
How about looking for the spaces surrounding the colon?
sed 's/ : .*//'
awk -F ' : ' '{print $1}'
You can use this sed:
str='2016-04-11 12:45:26 : TEXT TO REMOVE'
sed 's/ *:[^:]*$//' <<< "$str"
i.e. use [^:]*$ pattern to make sure we match last segment of line after last :
Output:
2016-04-11 12:45:26
Strictly speaking removing everything after the 3rd : is equivalent to print only the chars that are before it. sed would be easier to use that way.
Give this a try:
sed "s/^\([^:][^:]*:[^:][^:]*:[^:][^:]*\):.*$/\1/"
The same principle can be used to print only date time before ::
sed "s/^\([0-9][0-9]*-[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]\).*$/\1/g"
The chars in between the \( and the \) can be reused in the replacement section with \1.

Finding lines without letters or numbers, only with commas, BASH

Good day to all,
I was wondering how to find the line number of a line with only commas. The only but is that I don't know how many commas have each line:
Input:
...
Total,Total,,,
,,,,
,,,,
Alemania,,1.00,,
...
Thanks in advance for any clue
You can do this with a single command:
egrep -n '^[,]+$' file
Line numbers will be prefixed.
Result with your provided four test lines:
2:,,,,
3:,,,,
Now, if you only want the line numbers, you can cut them easily:
egrep -n '^[,]+$' file | cut -d: -f1
sed
sed -n '/^,\+$/=' file
awk
awk '/^,+$/&&$0=NR' file
With GNU sed:
sed -nr '/^,+$/=' file
Output:
2
3

Display all fields except the last

I have a file as show below
1.2.3.4.ask
sanma.nam.sam
c.d.b.test
I want to remove the last field from each line, the delimiter is . and the number of fields are not constant.
Can anybody help me with an awk or sed to find out the solution. I can't use perl here.
Both these sed and awk solutions work independent of the number of fields.
Using sed:
$ sed -r 's/(.*)\..*/\1/' file
1.2.3.4
sanma.nam
c.d.b
Note: -r is the flag for extended regexp, it could be -E so check with man sed. If your version of sed doesn't have a flag for this then just escape the brackets:
sed 's/\(.*\)\..*/\1/' file
1.2.3.4
sanma.nam
c.d.b
The sed solution is doing a greedy match up to the last . and capturing everything before it, it replaces the whole line with only the matched part (n-1 fields). Use the -i option if you want the changes to be stored back to the files.
Using awk:
$ awk 'BEGIN{FS=OFS="."}{NF--; print}' file
1.2.3.4
sanma.nam
c.d.b
The awk solution just simply prints n-1 fields, to store the changes back to the file use redirection:
$ awk 'BEGIN{FS=OFS="."}{NF--; print}' file > tmp && mv tmp file
Reverse, cut, reverse back.
rev file | cut -d. -f2- | rev >newfile
Or, replace from last dot to end with nothing:
sed 's/\.[^.]*$//' file >newfile
The regex [^.] matches one character which is not dot (or newline). You need to exclude the dot because the repetition operator * is "greedy"; it will select the leftmost, longest possible match.
With cut on the reversed string
cat youFile | rev |cut -d "." -f 2- | rev
If you want to keep the "." use below:
awk '{gsub(/[^\.]*$/,"");print}' your_file

Get substring from file using "sed"

Can anyone help me to get substring using sed program?
I have a file with this line:
....
define("BASE", "empty"); # there can be any string (not only "empty").
....
And I need to get "empty" as string variable to my bash script.
At this moment I have:
sed -n '/define(\"BASE\"/p' path/to/file.ext
# returns this line:
# define("BASE", "empty");
# but I need 'empty'
UPD: Thanks to #Jaypal
For now I have bash script:
DBNAME=`sed -n '/define(\"BASE\"/p' path/to/file.ext`
echo $DBNAME | sed -r 's/.*"([a-zA-Z]+)".*/\1/'
It work OK, but if there any way to make the same manipulation with one line of code?
You should use is
sed -n 's/.*\".*\", \"\(.*\)\".*/\1/p' yourFile.txt
which means something (.*) followed by something in quotes (\".*\"), then a comma and a blank space (,), and then again something within quotes (\"\(.*\)\").
The brackets define the part that you later can reuse, i.e. the string within the second quotes. used it with \1.
I put -n front in order to answer the updated question, to get online the line that was manipulated.
This should help -
sed -r 's/.*"([a-zA-Z]+)"\);/\1/' path/to/file.ext
If you are ok with using awk then you can try the following -
awk -F\" '/define\(/{print $(NF-1)}' path/to/file.ext
Update:
DBNAME=$(sed -r '/define\(\"BASE\"/s/.*"([a-zA-Z]+)"\);/\1/' path/to/file.ext)
sed -nr '/^define.*"(.*)".*$/{s//\1/;p}' path/to/file.ext
if your file doesn't change over time (i.e. the line numbers will always be the same) you can take the line, and use delimiters to take your part out:
`sed -n 'Xp' your.file | cut -d ' ' -f 2 |cut -d "\"" -f 2`
assuming X is the line number of your required line

Resources