1

I want to move lines from a text file into another text file. Those lines contain a word beginning with an underscore. This word is located on the sixth field of the lines; fields are separated with forward slashes. For example, move lines containing _Nokia on the sixth field, in the sample input file, below.

Apple/One-plus/Samsung/Mi/Sony/_Nokia/
Apple/One-plus/Samsung/Mi/Lenovo/_Nokia/
Apple/One-plus/Samsung/Mi/HTC/OPPO/

I have tried to move corresponding lines, with a regular expression, using grep, but it does not work.

$ grep -F 'Apple/One-plus/Samsung/Mi/^[a-zA-Z]([\w -]*[a-zA-Z])?$/_Nokia/' match.txt >file1.txt
$ grep -F -v "Apple/One-plus/Samsung/Mi/^[a-zA-Z]([\w -]*[a-zA-Z])?$/_Nokia/" match.txt \
    > match.txt.tmp && mv match.txt.tmp match

Expected output

$ cat file1.txt
Apple/One-plus/Samsung/Mi/Sony/_Nokia/
Apple/One-plus/Samsung/Mi/Lenovo/_Nokia/
$ cat match
Apple/One-plus/Samsung/Mi/HTC/OPPO/

How to move a line from a file to the other file on the basis of pattern matching?

1
  • Thank you @Fólkvangr for your suggestion, I am new here so I am not aware of rules but apologies for confusing you here. I have updated my question
    – sam
    Commented Sep 9, 2018 at 12:10

4 Answers 4

1

Original issue

A regular expression cannot be specified with the -F option concerning grep. There is another issue concerning the regular expression. If the character ^ is used as an anchor to match the beginning of a line, then, it must be the first character of the regular expression.

prompt% cp -v input input.back
prompt% grep -e "$regex" input.back > output
prompt% grep -v "$regex" input.back > input

Regular expression: the original poster did not provide a concrete input, therefore, it is difficult to find a suitable regular expression.

Edit: finally, the original poster has provided a sample input file.

Apple/One-plus/Samsung/Mi/Sony/_Nokia/
Apple/One-plus/Samsung/Mi/Lenovo/_Nokia/
Apple/One-plus/Samsung/Mi/HTC/OPPO/

Regular expression: regex

regex='\([-[:alpha:]]\+\/\)\{5\}_Nokia\/'

Alternative solutions

These similar solutions are not recommended for beginners whom have never read the sed manual.

sed -n "/$regex/p;/$regex/d;w input" input.back > output

Roughly speaking, the lines matching the regular expression are saved in the file output, then, they are deleted from the corresponding sed buffer and the buffer content is written in the file input.

sed -i.back -e "/$regex/w output" -e "/$regex/d" input

These commands have subtle differences but the second one is more convenient.

0

If you have a suitably recent version of GNU awk (gawk) you could do

awk -i inplace -F'/' '$7 == "_f" {print > "otherfile"; next} 1' file

If your awk doesn't support the -i inplace option, then you can do the same thing but redirect the output to a temporary file and then rename it.

2
  • what's the point of the next there? it's not a useless usage for single block? Commented Sep 7, 2018 at 4:27
  • @αғsнιη the next is what turns it from a copy to a move (i.e. it prints to otherfile, but skips the default print to the original file) Commented Sep 7, 2018 at 11:05
0

How about this proposition? This is a less concise proposition than @steeldriver's answer, nonetheless, it is a progressive solution (step by step).

$ cut -d/ -f7 data.txt  | grep -n _f | cut -d: -f 1 | xargs -i sed -n {}p data.txt > otherfile.txt
  • _f is the pattern when matched is created to the other file.

  • data.txt is your file

  • / is your delimiter

If this worked, then do a comm to work out what should remain in the original file.

$ comm -23 data.txt otherfile.txt > remainder.txt

remainder.txt is your data.txt with the bits removed.

5
  • Thanks @Rui first part is working fine as per the requirement but second command $ comm -1 data.txt otherfile.txt > remainder.txt is not working as per the requirement basically it is only creating new file with out moving data from original file.
    – sam
    Commented Sep 9, 2018 at 12:14
  • Doesnt remainder.txt have the contents of what you want? If so, then rename remainder.txt to be data.txt and you have your solution, no?
    – Chai Ang
    Commented Sep 9, 2018 at 22:39
  • no, remainder.txt is containing the same data as otherfile.txt. I have tried comm -23 otherfile.txt data.txt but no luck.
    – sam
    Commented Sep 10, 2018 at 7:43
  • My mistake... comm -23 is what you want. I have edited the answer. Order of the files makes a difference.
    – Chai Ang
    Commented Sep 10, 2018 at 9:25
  • As in comm -23 otherfile.txt data.txt will not give you what you want BUT comm -23 data.txt otherfile.txt will give you what you want.
    – Chai Ang
    Commented Sep 11, 2018 at 5:57
0

You can first move the intended lines to the other file (outemp.txt) by:

sed -n  '/_/w outemp.txt' input_file

then remove those lines from your input_file by:

sed  -i '/_/d' input_file

check the result:

cat outemp.txt 
Apple/One-plus/Samsung/Mi/Sony/_Nokia/
Apple/One-plus/Samsung/Mi/Lenovo/_Nokia/

cat input_file
Apple/One-plus/Samsung/Mi/HTC/OPPO/

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .