How to print File name in the same file? - linux

I have a file with around 5 lines and I want to have the file name printed at the end of every line.
for file in *.txt
do
sed -i "1s/\$/${file%%.*}/" "$file"
done
The above code only writes file name in first line, I want to have file name in every line.

The above code only writes file name in first line
This is what the 1 on the beginning of the sed command does: it is an address that selects the lines processed by the command.
In your case, the s command applies only to the first line (because of 1 in front of the command). Remove the 1 from the command and it will apply to all lines of the file:
for file in *.txt
do
sed -i "s/\$/${file%%.*}/" "$file"
done
Read more about sed at https://www.gnu.org/software/sed/manual/sed.html.
Given that you have already learned sed, typing man sed on your terminal will refresh your memory about its commands.

This is a bit hacky, but it does the trick (bash):
filename=<filename>; len=$(wc -l $filename | cut -f1 -d' '); for i in $(seq $len); do echo $filename; done | paste $filename -
And this is cleaner, but needs python installed:
python -c "import sys; print('\n'.join(line.rstrip() + '\t' + sys.argv[1] for line in open(sys.argv[1])))" <filename>

Related

Filter a text from a specific file and append the output to another file Linux

I am trying to append a text from a file to the another file in Linux using the grep command .
I have a file named "temp1buildVersion.properties" which contain the data
like
Project version: 1.0.5
also, I have another file named buildversion.properties which contain data
VERSION_BUILD=
I want to fetch content from temp1buildVersion.properties" after "Project version:" and append it to an existing file named "buildversion.properties"
so that output of the buildversion.properties will be
VERSION_BUILD=1.0.5
currently, I am doing using the grep command to fetch data and appending output to file " buildversion.properties "
grep 'Project version: ' /tmp/tempbuildVersion.properties | cut -d\ -f3 >> /tmp/buildversion.properties
it comes in two-line How can I append to the same line /or a specific line?
VERSION_BUILD =
1.0.5
You may use this awk:
awk -F ': ' 'FNR==NR {ver=$2; next} /^VERSION_BUILD=/ {print $0 ver}' temp1buildVersion.properties buildversion.properties > _tmp && mv _tmp buildversion.properties
VERSION_BUILD=1.0.5
Another option is using sed to append to the end of the line, e.g.
sed "/VERSION_BUILD/s/\$/$(grep 'Project version: ' /tmp/tempbuildVersion.properties | cut -d\ -f3)/" buildversion.properties
Above your command is simply placed as a command substituion in sed "/VERSION_BUILD/s/\$/$(your_cmd)/" file. You would add sed -i to update the file in place.
You can eliminate the pipeline and cut by simply using awk to isolate the version number and shorten the command a bit, e.g.
sed "/VERSION_BUILD/s/\$/$(awk '/^Project version:/{printf "%s", $NF; exit}' /tmp/tempbuildVersion.properties)/" buildversion.properties
If ed is available/acceptable.
printf '%s\n' 'r temp1buildVersion.properties' 's/^Project version: //' '1,$j' ,p Q | ed -s buildversion.properties
Change Q to w if you're ok with the output and to edit the file buildversion.properties
The script.
#!/usr/bin/env bash
ed -s "$1" <<-EOF
r $2
s/^Project version: //
1,\$j
,p
Q
EOF
You can execute with the files as the arguments.
./myscript buildversion.properties temp1buildVersion.properties
This might work for you (GNU sed):
sed -i '/VERSION_BUILD=/{x;s/.*/cat fileVersion/e;x;G;s/\n.*:\s*//}' fileBuild
Process the build file until a match on a line VERSION_BUILD=.
Swap to the hold space and insert the version file line.
Append the line from the version file to the current line and using pattern matching manipulate the line into the desired format.

Linux command to replace set of lines for a group of files under a directory

I need to replace first 4 header lines of only selected 250 erlang files (with extension .erl), but there are 400 erlang files in total in the directory+subdirectories, I need to avoid modifying the files which doesn't need the change.
I've the list of file names that are to be modified, but don't know how to make my linux command to make use of them.
sed -i '1s#.*#%% This Source Code Form is subject to the terms of the Mozilla Public#' *.erl
sed -i '2s#.*#%% License, v. 2.0. If a copy of the MPL was not distributed with this file,#' *.erl
sed -i '3s#.*#%% You can obtain one at http://mozilla.org/MPL/2.0/.#' *.erl
sed -i '4s#.*##' *.erl
in the above commands instead of passing *.erl I want to pass those list of file names which I need to modify, doing that one by one will take me more than 3 days to complete it.
Is there any way to do this?
Iterate over the shortlisted file names using awk and use xargs to execute the sed. You can execute multiple sed commands to a file using -e option.
awk '{print $1}' your_shortlisted_file_lists | xargs sed -i -e first_sed -e second_sed $1
xargs gets the file name from awk in a $1 variable.
Try this:
< file_list.txt xargs -1 sed -i -e 'first_cmd' -e 'second_cmd' ...
Not answering your question but a suggestion for improvement. Four sed commands for replacing header is inefficient. I would instead write the new header into a file and do the following
sed -i -e '1,3d' -e '4{r header' -e 'd}' file
will replace the first four lines of the file with header.
Another concern with your current s### approach is you have to watch for special chars \, & and your delimiter # in the text you are replacing.
You can apply the sed c (for change) command to each file of your list :
while read file; do
sed -i '1,4 c\
%% This Source Code Form is subject to the terms of the Mozilla Public\
%% License, v. 2.0. If a copy of the MPL was not distributed with this file,\
%% You can obtain one at http://mozilla.org/MPL/2.0/.\
' "$file"
done < filelist
Let's say you have a file called file_list.txt with all file names as content:
file1.txt
file2.txt
file3.txt
file4.txt
You can simply read all lines into a variable (here: files) and then iterate through each one:
files=`cat file_list.txt`
for file in $files; do
echo "do something with $file"
done

Linux - Get a line from one file and corresponding line from a second file and pass into cp command

I have two .txt files.
'target.txt' is a list of target files
'destination.txt' is a list of (on corresponding lines) of destinations.
I'd like to create a command that does the following:
cp [line 1 from target.txt] [line 1 from destination.txt]
For each line of the files.
paste target.txt destination.txt | sed -e 's/^/cp /' > cp.cmds
Then, after inspecting cp.cmds for correctness, you can just run it as a shell script.
sh cp.cmds
The paste command merges two files by concatenating corresponding lines.
paste target.txt destination.txt | while read target dest; do
cp $target $dest
done
This will not work if any of the filenames contain spaces, though. If that's a requirement, I would use awk to read the first file into an array, then when reading the second file print a cp command with the corresponding lines and quotes around them, and pipe this to sh to execute it.
To handle whitespace in the filenames:
paste -d\\n target.txt destination.txt | xargs -d\\n -n2 -x cp
paste -d\\n interleaves lines of the argument files
xargs -d\\n -n2 reads two complete lines at a time and applies them as two arguments at the end of the command line. The -d flag disables all special processing of quotes, apostrophes and backslashes in the input lines, as well as the eof character (by default _).
The -d command-line options to xargs is a GNU extension. If you are stuck with a Posix standard xargs, you can use the following alternative, courtesy of the Open Group (see example 2, near the end of the page):
paste -d\\n target.txt destination.txt |
sed 's/[^[:alnum:]]/\\&/g' |
xargs -E "" -n 2 -x cp
The sed command backslash-escapes every non-alphanumeric character
xargs -E "" disables the end-of-file character handling.

How do i copy every line X line from a bunch of files to another file?

So my problem is as follows:
I have a bunch of files and i need only the information from a certain line in each of these files (the same line for all files).
Example:
I want the content of the line 10 from file example_1.dat~example_10.dat and then i want to save it on > test.dat
I tried using: head -n 5 example_*.dat > test.dat. But this gives me all the information from the top till the line i have chosen instead of just the line.
Please help.
$ for f in *.dat ; do sed -n '5p' $f >> test.dat ; done
This code will do the following:
Foreach file f in the directory that ends with .dat.
Use sed on the 5:th row in file and write to test.dat.
The ">>" will add the row at the bottom of the file if existing.
Use a combination of head and tail to zoom to the needed line. For example, head -n 5 file | tail -n 1
You can use a for loop to get it done over several files
for f in *.dat ; do head -n 5 $f | tail -n 1 >> test.dat ; done
PS: Don't forget to clean the test.dat file (> test.dat) before running the loop. Otherwise you'll get results from previous runs as well.
You can use sed or awk:
sed -n "5p"
awk "NR == 5"
This might work for you (GNU sed):
sed -sn '5wtest.dat' example_*.dat

Find line number in a text file - without opening the file

In a very large file I need to find the position (line number) of a string, then extract the 2 lines above and below that string.
To do this right now - I launch vi, find the string, note it's line number, exit vi, then use sed to extract the lines surrounding that string.
Is there a way to streamline this process... ideally without having to run vi at all.
Maybe using grep like this:
grep -n -2 your_searched_for_string your_large_text_file
Will give you almost what you expect
-n : tells grep to print the line number
-2 : print 2 additional lines (and the wanted string, of course)
You can do
grep -C 2 yourSearch yourFile
To send it in a file, do
grep -C 2 yourSearch yourFile > result.txt
Use grep -n string file to find the line number without opening the file.
you can use cat -n to display the line numbers and then use awk to get the line number after a grep in order to extract line number:
cat -n FILE | grep WORD | awk '{print $1;}'
although grep already does what you mention if you give -C 2 (above/below 2 lines):
grep -C 2 WORD FILE
You can do it with grep -A and -B options, like this:
grep -B 2 -A 2 "searchstring" | sed 3d
grep will find the line and show two lines of context before and after, later remove the third one with sed.
If you want to automate this, simple you can do a Shell Script. You may try the following:
#!/bin/bash
VAL="your_search_keyword"
NUM1=`grep -n "$VAL" file.txt | cut -f1 -d ':'`
echo $NUM1 #show the line number of the matched keyword
MYNUMUP=$["NUM1"-1] #get above keyword
MYNUMDOWN=$["NUM1"+1] #get below keyword
sed -n "$MYNUMUP"p file.txt #display above keyword
sed -n "$MYNUMDOWN"p file.txt #display below keyword
The plus point of the script is you can change the keyword in VAL variable as you like and execute to get the needed output.

Resources