I have a number of .conf files that are identical and in the same directory, with the exception of having different file names. In each uniquely named .conf file, I would like to replace a set of characters in the file with the name of the file. For example:
Currently in all files:
datafname = example.nex
ofprefix = best.exampleIdeal output:
Filename: 25.conf
datafname = 25.nex
ofprefix = best.25Filename: 26.conf
datafname = 26.nex
ofprefix = best.26I thought that I could use sed to run through all these files to find and replace the string of text with the file name using something like:
sed -i conf 's/example/echo $f/g' *but this is not working properly. Would anyone happen to have a suggestion on how to do this?
04 Answers
You can do:
for f in *.conf; do base=$(basename "$f" '.conf') # gives '25' from '25.conf' sed -i.before "s/example/$base/g" "$f"
doneWhen using the -i switch to sed, you must be absolutely sure that your sed command works because -i changes the files in-place. This means the generated output will overwrite the input file. If your replacement command (s/…/…/) is wrong, you may end up with empty files and no backups. Hence, I used -i.before which will leave a *.before file with the original content.
You can use a for loop to iterate over the files. Use parameter expansion to remove the file extension. Use double quotes around the expression, otherwise the variable wouldn't be expanded.
#! /bin/bash
for f in *.conf ; do b=${f%.conf} sed -i "s/example/$b/" "$f"
done 0 You can do the task without a loop using GNU parallel :
parallel sed -i.old s/example/{.}/ {} ::: *.confThis is especially useful if you have a lot of files to edit, as parallel runs one job per CPU core.
-i.oldmeans: edit the filein-place and make a backup adding the.oldextension to the original filename (remove.oldif you don't want a backup, but remember you don't have a backup then)s/example/{.}/gmeanssubstituteexamplewith the input filename without its extension ({.}) and do itglobally (= to every occurence){}is replaced with the input filename:::separates the command to run from the arguments to pass to it*.confmatches every.conffile in the current directory
With awk, which has a FILENAME variable automatically set to the filename (and, if GNU awk, with edits in-place as well):
$ for i in {20..26}; do printf "%s\n" "datafname = example.nex" "ofprefix = best.example" > $i.conf; done
$ gawk -i inplace 'FNR == 1 {split(FILENAME, file, ".")} {gsub("example", file[1])} 1' *.conf
$ cat 25.conf
datafname = 25.nex
ofprefix = best.25FNR == 1 {split(FILENAME, file, ".")}: on the first line of each file, split the filename on.and store it in thefilearray{gsub("example", file[1])} 1: for all lines, replaceexamplewith the first element of thefilearray and print.