This question already has answers here:
Difference between single and double quotes in Bash
(7 answers)
Closed 4 years ago.
I am very new to this all and have used this website to help me find the answers i'm looking for.
I want to replace a line in multiple files across multiple directories. However I have struggled to do this.
I have created multiple directories 'path_{0..30}', each directory has the same 'input' file, and another file 'opt_path_rx_00i.xyz' where i corresponds to the directory that the file is in (i = {0..30}).
I need to be able to change one of the lines (line 7) in the input file, so that it changes with the directory that the input file is in (path_{0..30}). The line is:
pathfile opt_path_rx_00i.xyz
Where i corresponds to the directory that the file is in (i={0..30})
However, i'm struggling to do this using sed. I manage to change the line for each input file in the respective directories, but i'm unable to ensure that the number i changes with the directory. Instead, the input file in each directory just changes line 7 to:
pathfile opt_path_rx_00i.xyz
where i, in this case, is the letter i, and not the numbers {0..30}.
I'll show what i've done below in order to make more sense.
for i in {0..30}
do
sed -i '7s/.*/pathfile-opt_path_rx_00$i.xyz/' path_$i/input
done
What I want to happen is, for example in directory path_3, line 7 in the input file will be:
pathfile opt_path_rx_003.xyz
Any help would be much appreciated
can you try with double quotes
for i in {0..30}; do
sed -i "7s/.*/pathfile-opt_path_rx_00$i.xyz/" "path_$i/input"
done
Related
This question already has answers here:
remove date from filename but keep the file extension
(2 answers)
Closed 4 years ago.
Is there a quick and clever way to remove various timestamps from multiple files with different names? The timestamp format always remains the same, although the values differ. An example of my files would be...
A_BB_CC_20180424_134312
A_B_20180424_002243
AA_CC_DD_E_20180424_223422
C_DD_W_E_D_20180423_000001
with the expected output
A_BB_CC
A_B
AA_CC_DD_E
C_DD_W_E_D
Notice the last file has a different timestamp, I don't mind if this is a day specific timestamp removal or all, or two variations. My problem is I can't think of the code for an ever changing time value :(
Thanks in advance
EDIT - Adding edit in to show why this is not a duplicate as Tripleee thinks. His duplicate link is for files with the same prefix, my question is about files with different names so the answer is different.
Using parameter expansion %% bashism that removes the end of the filename:
for i in /my/path/*; do mv "$i" "${i%%_2018*}"; done
This relies on the timestamp that start with 2018...
Using awk:
for i in /my/path/*; do mv "$i" $(awk -v FS=_ 'NF-=2' OFS="_" <<< "$i"); done
This awk script is based on the field separator _. It prints the filename without the last 2 field representing the timestamp.
In order to rename a set of files and apply regular expressions in the renaming process you can use the rename command.
So in your example:
rename 's#_[0-9]*_[0-9]*##' *_[0-9]*
This renames all files in the current directory ending with _ followed by digits.
It cuts away all _ followed by digits followed by _ followed by digits.
This question already has answers here:
How to change a command line argument in Bash?
(3 answers)
How to compare timestamp on files in bash scripting
(3 answers)
Closed 5 years ago.
I often use exiftool to copy metadata from one file to another.
exiftool -TagsFromFile FILE1[SOURCE] FILE2[TARGET]
I am trying to speed up the workflow and figure out a bash script that would allow me to simply select two files in file explorer - right click on them - open with - thescript.sh
/path/to/thescript.sh $1 $2
As you can see the most important part is to select a right file as the source ($1) / target ($2).
Source files often named like this:
20170630_181348_2674.jpg or 20170630_181348_2674.dng
Target files usually have a suffix added to the name e.g. 20170630_181348_2674_0001.jpg or 20170630_181348_2674_v2.jpg
So one thing I know for sure is that the source file name is always shorter.
Another thing, the files I use as the source are always older than the ones I copy metadata to.
I was wondering if there is any way in bash to compare inputs ($#) by their file name or by the file modify date and place them as $1 and $2 accordingly.
Any ideas would be greatly appreciated.
This question already has answers here:
Find and replace in file and overwrite file doesn't work, it empties the file
(12 answers)
Closed 6 years ago.
I am working on a bash script and running into a problem with sed leaving the file that I am using it to clean blank.
Here is the blocks that define the file and the function that I created to clean the file:
# Define Review Log file
reviewlog=/home/serverreview-$(date +%d%^b%y).txt
# Bleachs the Review Log of the color customization
bleach ()
{
sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g" $reviewlog >> $reviewlog
}
Using the >> it does append the info to the bottom of the file as it is supposed to. However if I use:
bleach ()
{
sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g" $reviewlog > $reviewlog
}
It leaves the output file totally blank
This is normal as sed reads as it writes. The first write will truncate the file. This ends reading and leaves an empty file.
In some condition when a tool reads a buffer before writing it would work for small inputs. But this is nothing you dont want to depend on. so if the tool does not have a in-place overwrite option don't use it.
You can write to a temp outfile and rename it over the infile or rename the in-file (or open the in-file, then delete it) and then write to the expected location. Otherwise you have to ensure to read everything into memory.
sed -i with and without extension does work the same. See for example https://robots.thoughtbot.com/sed-102-replace-in-place which describes the -i variations.
This question already has answers here:
Editing/Replacing content in multiple files in Unix AIX without opening it
(2 answers)
Closed 6 years ago.
I wonder know if there is a way to edit a conf file without getting in the file and changing the lines?
In my case, I need to edit zabbix-agent conf file (located in /etc/zabbix/zabbix_agentd.conf) and there are some parameters in the file that I need to change, such as Server Name, DebugLevel, and others.
Normally I edit the file using vim and change the lines, but my idea is to edit the file directly from bash, but I don`t know if this is possible.
For example, if I need to change the parameter DebugLevel, at bash I would run:
# /etc/zabbix/zabbix_agentd.conf.DebugLevel=3
This actually doesn`t works, but I would like something like this for my problem...
Does anyone knows??
I tested what David said, but it didn`t solved my problem... There are some lines in the file that is commented and I need to uncomment them, and there are some lines that I just need to change.
For example, the line above:
# DebugLevel=3
I need to change to:
DebugLevel=3
And this line:
Server=127.0.0.1
I need to change for the IP of zabbix server name, like this:
Server=172.217.28.142
Is there any other way?
If I understand your question correctly, then you want sed -i (the -i option allows sed to edit the file in place, and -i.bak will do the same but create a backup of the original file with the .bak extension)
To change DebugLevel=3 to DebugLevel=4 in file /etc/zabbix/zabbix_agentd.conf, you can do:
# sed -i.bak "/DebugLevel/s/[0-9][0-9]*$/4/" /etc/zabbix/zabbix_agentd.conf
If I misinterpreted your question, please let me know.
To Change Values at the End
Example Input File
$ cat file.txt
DebugLevel=3
Example Use
$ sed -i "/DebugLevel/s/[0-9][0-9]*$/4/" file.txt
$ cat file.txt
DebugLevel=4
To Remove Comments
You can do virtually the same thing to uncomment the parameters of interest, for example:
# sed -i.bak "/DebugLevel/s/^#//" /etc/zabbix/zabbix_agentd.conf
In each case, sed is searching for the label in the first set of forward slashes /.../, next the substitute command is called s and then the expression between the next set of forward slashes, e.g. /^#/ (^ match at the beginning), if matched, is replaced by what follows in the next set // (nothing in the remove comment case).
You will need to adjust the values as required to match each parameter you need to find and replace. Let me know if you have further problems and exactly what the problem is.
This question already has answers here:
How to remove the lines which appear on file B from another file A?
(12 answers)
Closed 9 years ago.
I’ve got two text files, each with several hundred lines. Some of the lines exist in both files, and I want to remove those so that they exist in only one of the files. Basically, I want to reduce them to get a unique set of lines. The catch is that I can’t sort them (they are stripped-down dumps of my Chromium history).
What is the easiest way to do this?
I tried WinDiff, but that gave incorrect results. I figure that I could knock together a PHP script in a while, but am hoping that there is an easier way (preferably a command-line tool).
Well, I ended up writing a PHP script after all.
I read both files into a string, then exploded the strings into arrays using \r\n as the delimiter. I then iterated through the arrays to remove any elements that exist, and finally dumped them back out to a file.
The only problem was that by trying to refactor the stripping routine to a function, I found that passing the array that gets changed (elements removed) by reference caused it to slow down to the point of needing to be Ctrl-C’d, so I just passed by value and returned the new array (counterintuitive). Also, using unset to delete the elements was slow no matter what, so I just set the element to an empty string and skipped those during the dump.
If you have a bash shell (cygwin), the following shell commands would remove all lines that appear in both files from a.txt:
comm -12 <(sort a.txt|uniq) <(sort b.txt|uniq) | while read dupe; do dupe_escaped=$(echo "$dupe" | sed 's/[][\.*^$/]/\\&/g'); sed -e "/${dupe_escaped}/d" -i a.txt; done