How to selectively copy details from a file and paste them into a new file?
I have a file containing my personal details (.txt). How can I via the terminal copy only a few details from the file and put those into a new .txt
file?
For example, if this is the content of the file:
name : farah age : 23 phone number : 0123 education : degree
how can I copy only age and phone number and output those to a new .txt
file?
There are several ways to do this. If your file has some known structure, you can use grep
. The grep
command searches a file for a specific phrase and returns lines that match that phrase. So if your file looks like
Name: Sally
Date of Birth: 7.31.76
Address: 1234 Main St.
SSN: 123-45-6789
you can run grep Name info.txt
and it will return Name: Sally
. You can then redirect the output to another file. So calling
grep Name info.txt > info2.txt
will output the line to the new file info2.txt. If you want to append new lines, you can do
grep Address info.txt >> info2.txt
otherwise the file will be overwritten.
You could also learn to use a command line text editor like vim.
You can use grep to search for a regular expression in details.txt and redirect the result to the new file.
If all the lines you want to copy have something in common the other lines don't you can use :
grep "string in common" details.txt > new.txt
If not you will have to search for each line you want to copy, still using grep, and append them to new.txt using >>
in stead of >
.
The file you showed has all the details on one line:
name : farah age : 23 phone number : 0123 education : degree
I have assumed that you can hard-code age :
etc into the command, but the text following it will vary, and that the details may not be in the given order or be contiguous.
You can extract parts of the line with grep
's -o
flag. This prints only the matched part, rather than the whole line.
If you want to include the age :
and phone number :
parts, you can either use the -e
flag to specify multiple matches, or alternation.
$ grep -oe 'age : [^ ]*' -e 'phone number : [^ ]*' file
age : 23
phone number : 0123
The expression [^ ]*
means any number of characters that are not a space, so it matches characters after age :
up to the next space.
Replace file
with the name of the file that contains your details. You may write the new file by redirecting the output to a new file with the >
operator, like this:
grep -oe 'age : [^ ]*' -e 'phone number : [^ ]*' file > outfile
When you do that, you won't see any output. You should check the output first, then add redirection.
Here's the example with alternation. We use the -E
flag to tell grep
to use extended regex. The syntax is (pattern1|pattern2)
- this matches pattern1
and/or pattern2
. If either is found, it will be printed (regardless of whether the other is found or not). I'm now using +
meaning at least one of the preceding character, instead of *
meaning zero or more of the preceding character. In this context, they both work equally well.
$ grep -Eo '(age : [^ ]+|phone number : [^ ]+)' file
age : 23
phone number : 0123
If you want to omit the age :
and phone number:
parts, you can use the -P
flag to ask grep
to use Perl-compatible regular expressions. This supports alternation, and also a way of matching text after a given pattern:
$ grep -Po '(age : \K[^ ]+|phone number : \K[^ ]+)' file
23
0123
If you want to format the text differently, you can use sed
, for example:
$ sed -r 's/.*(age) : ([^ ]*).*(phone number) : ([^ ]*).*/\1:\2 | \3:\4/' file
age:23 | phone number:0123
This depends on age
coming before phone number
, so adjust accordingly if that's not the case. If you can't rely on the order, you can use this very convoluted command:
$ sed -r 's/(.*)(phone number : [^ ]+)(.*) .*/\2 \1\4/; s/(phone number) : ([^ ]+) .*(age) : ([^ ]+).*/\1: \2 | \3: \4/' file
phone number: 0123 | age: 23
This rearranges the line so that the phone number :
section comes first on every line, then does a second replacement to select the desired details. I owe the technique used here to this answer by muru.
Notes on sed
commands not covered by previous explanations
-
-r
use extended regex for more readable commands (GNUsed
understands-E
with the same meaning) -
s/old/new/
replaceold
withnew
-
(pattern)
savespattern
to reference later, with\1
or\2
etc (corresponding to the left-to-right order in which the capture groups occur - note thatsed
will only hold up to 7 of these!). -
.
any character, therefore.*
represents any number of any characters. -
;
separates commands, as in the shell.
There are also editors which work in the terminal, e.g. nano, vi and emacs.
If you are using a graphical user interface on your local machine and a terminal on a remote machine, you can also use the mouse to copy and paste from one terminal window/tab to a second one.
Assuming input file details.txt
contains:
name: farah
age: 23
phone number: 0123
education: degree
you can select lines "name" and "phone" by extended grep and redirect output to new.txt:
grep -E "age:|phone number:" details.txt > new.txt
This will produce new.txt with:
age: 23
phone number: 0123
How it works:
Grep prints only matched lines. The -E
options enabled extended regexp which gives you possibility to use |
(alternative). Remember to quote whole pattern, so |
will be interpreted by grep. Otherwise shell will try to interpret. You don't want this here.