-3

I am trying to solve a problem in which I am given a few lines for eg:

abdkfsj | kfjlds | james
sdlfjk | sfdjsldfjk | andrew
sdjfsdl | dskljoer | james

I was asked to find the lines which contain james and print them in reverse order the output of above example will be-

james | kfjlds | abdkfsj
james | dskljoer | sdjfsdl

Can someone please tell me how to solve this and what command will be used to solve this question in unix using shell scripting?

Tried this:

awk -F"|" '{ print $3 $2 $1}' | grep --line-buffered james input.txt 
Til
  • 5,150
  • 13
  • 26
  • 34
Divesh Sankhla
  • 53
  • 2
  • 13
  • I don't understand how to solve this I had tried grep command with awk – Divesh Sankhla Feb 10 '19 at 10:02
  • 1
    awk -F"|" '{ print $3 $2 $1}' | grep --line-buffered james input.txt – Divesh Sankhla Feb 10 '19 at 10:06
  • Better [edit](https://stackoverflow.com/posts/54615218/edit) into your question :) – Til Feb 10 '19 at 10:24
  • 1
    In both your input and output examples you show a _space_ character on each side of the _pipe_ character, so is the delimiter _space_ | _space_ or is it just `|`? If you added the _space_ for clarity you should note that! Samples of _input_ and _output_ should always be shown as explicitly what is and what is expected! – user3439894 Feb 10 '19 at 17:31
  • 1
    It's better to give us some feedback, instead of just ask a question and leave it there, if you are too busy then come when you have reasonably enough time for it. Please read [how-to-ask](https://stackoverflow.com/help/how-to-ask), [mcve](https://stackoverflow.com/help/mcve), and [someone-answers](http://stackoverflow.com/help/someone-answers). – Til Feb 10 '19 at 18:25
  • Actually "|" is delimiter, I had put space just to make the input and o/p shows clearly here that's it In actual there is no space only "|" seperate the words @user3439894 – Divesh Sankhla Feb 11 '19 at 07:33

4 Answers4

3
awk '/james/{for (i=NF; i>1; i--) printf "%s%s", $i, FS; print $i}' file

If line contains james output its columns in reverse order.

Output:

james | kfjlds | abdkfsj
james | dskljoer | sdjfsdl

Source: https://stackoverflow.com/a/21944886/3776858

Cyrus
  • 84,225
  • 14
  • 89
  • 153
  • A restriction: my code won't work if columns contain spaces or tabs: `abdkfsj | kfjlds | james smith` – Cyrus Feb 10 '19 at 11:41
  • Without this restriction and GNU awk: `awk -v FS=' \\| ' -v OFS=" | " '/james/{for (i=NF; i>1; i--) printf "%s%s", $i, OFS; print $i}' file` – Cyrus Feb 10 '19 at 12:09
1

Well, you are on the right way actually, just needs to set OFS, also add the condition:

awk -F'|' -v OFS="|" '/james/{print $3,$2,$1}' input.txt

So with this one command you can do the thing, no need to pipe to grep.

And if there're many columns to reverse:

awk -F'|' '/james/{for(i=1;i<=NF/2;i++){j=NF-i+1;t=$i;$i=$j;$j=t}print}' OFS='|' input.txt

Here I used a different approach by actually exchange high columns with low columns, and by assigning OFS before the input files, saved the necessity of -v.

Well, if you want to keep the spaces too, use these GNU awk solutions:

awk -F' *[|] *' -v OFS=' | ' '/james/{print $3,$2,$1}' input.txt
james | kfjlds | abdkfsj
james | dskljoer | sdjfsdl

$ awk -F' *[|] *' '/james/{for(i=1;i<=NF/2;i++){j=NF-i+1;t=$i;$i=$j;$j=t}print}' OFS=' | ' input.txt
james | kfjlds | abdkfsj
james | dskljoer | sdjfsdl
Til
  • 5,150
  • 13
  • 26
  • 34
  • @user3439894 Thanks for mention it, I already noticed that, however I thought that was just added by OP to better show the data. If you check OP's own code you can see OP's purpose. – Til Feb 10 '19 at 16:58
  • @user3439894 Anyway, what exactly OP wants only OP knows, so long OP don't show up and communicate, we can't be sure. And I think we answer questions on SO is to help OPs(and others, including ourselves) improve, not just do their work. So as long as my answers can give someone insights, I think it's enough. Btw, just fyi, not that it's important, it's me first upvoted Cyrus's answer. – Til Feb 10 '19 at 17:02
  • @user3439894 Updated. – Til Feb 10 '19 at 18:22
1

The syntax for the grep command to be given as input to the awk is incorrect. It needs little tweaking and adding OFS="|" in the BEGIN does the job. Check this out

 awk -F"|" 'BEGIN { OFS="|"} { print $3,$2,$1}' <(grep --line-buffered james divesh.txt)

with the inputs.

$ cat divesh.txt
abdkfsj | kfjlds | james
sdlfjk | sfdjsldfjk | andrew
sdjfsdl | dskljoer | james

$ awk -F"|" 'BEGIN { OFS="|"} { print $3,$2,$1}' <(grep --line-buffered james divesh.txt)
 james| kfjlds |abdkfsj
 james| dskljoer |sdjfsdl

$
stack0114106
  • 8,534
  • 3
  • 13
  • 38
1

You can try sed :

sed '/james/s/\([^|]*\)\( *| *\)\([^|]*\)\2\([^|]*\)/\4 \2\3\2\1/' infile
ctac_
  • 2,413
  • 2
  • 7
  • 17