greping and replacing 2 file paths - linux

I am currently working on a project where I would like to change a picture in multiple places.
old file dir: /images/icons/helpPop.png
new file dir: /public/website_pngs/icons-buttons/button_question_mark.png
I want to try
grep -rl 'images/icons/helpPop' . | xargs sed -i 's/images/icons/helpPop/public/website_pngs/icons-buttons/button_question_mark/g'
But I know that will not work. I am looking into delimiters and would like some extra advice please.

I am looking into delimiters and would like some extra advice please.
some suggestions:
if the old/new dirs are fixed, try to save them into variables
use different delimiter in sed e.g. "s#$old#$new#g" or "s#$old#$new#g" (double quotes!!)
to be safer, you better escape the . (period/dot) in your old dir text. since it indicates any char in regex. it could be a dangerous operation with plain text like that. (fortunately you don't have .* in your path ^_^ )
or you want the working codes?
EDIT for comment:
you don't need to "setup" the delimiter, just use it, like you are using /, take a look this example:
kent$ echo "/////"|sed 's#/#?#g'
?????
kent$ echo "/////"|sed 's^/^?^g'
?????
kent$ echo "/////"|sed 's%/%?%g'
?????
kent$ echo "/////"|sed 's;/;?;g'
?????

for i in grep -rl 'images/icons/helpPop' . ; do cp $i $i.bak; sed -i 's/images\/icons\/helpPop/public\/website_pngs\/icons-buttons\/button_question_mark/g' < $i.bak > $i; done

Related

How do I loop over multiple files to extract specific columns and save as separate files?

I have numerous *.txt files. I want to extract column 3 and 5 from each of these files and save them as new files keeping their oiginal names with new_ extension. I have this bash loop below in trying to do this, but doesn't do what I want. Can someone please help me with this?
for i in *.txt; do
cut -f 3,5 $i > /media/owner/new_$i_assembly.txt
done
Simple approach:
for f in *.txt; do
cut -d$'\t' -f3,5 "$f" > "/media/owner/new_${f}_assembly.txt"
done
In case if there could be possible whitespace(s) except tabs - you may use the following awk approach:
for f in *.txt; do
awk '{ print $3,$5 }' OFS='\t' "$f" > "/media/owner/new_${f}_assembly.txt"
done
You have to make sure and tell Bash explicitly to expand variable $i, otherwise it picks up characters you don't want and expands variable $i_assembly instead:
for i in *.txt; do
cut -f 3,5 "$i" > "/media/owner/new_${i}_assembly.txt"
done
If you don't want the extension included in your new name, use parameter expansion ${i%.*} that removes everything up to the first . included, from the end.
for i in *.txt; do
cut -f 3,5 "$i" > "/media/owner/new_${i%.*}_assembly.txt"
done
If you decide for a different approach that might result in paths, not just filenames (for example: **/*.txt), you can use parameter expansion once again to get only the name of your file:
for i in **/*.txt; do
base=${i##*/}
base=${base%.*}
cut -f 3,5 "$i" > "/media/owner/new_${base}_assembly.txt"
done
Also note that TAB is the default delimiter for cut, you don't need to specify it with the -d option:
-d, --delimiter=DELIM
use DELIM instead of TAB for field delimiter

Bash - Split dir string

I got the following string: '/transfer/IN/name/test.txt'
Now I'm trying to split this for the string name, cause I need it for further operations.
How can I split this correctly?
I've tried with cut (would sed be better?), but I'm not able to find the right approach.
Thanks for your help in advance.
This should help too:
awk -F'/' '{print $(NF-1)}' <<<"/a/b/c/d"
And it outputs:
c
If you like using sed:
sed 's#/[^/]*$##;s#.*/##' <<<"/a/b/c/d"
Just use the proper tools dirname and basename chained together:
echo $(basename $(dirname /transfer/IN/name/test.txt))
dirname => /transfer/IN/name
basename => name
sed solution looks more complex BTW:
sed -e "s#.*/\([^/]*\)/[^/]*#\1#" -e "s#/.*##" <<< name/test.txt
(2 expressions to handle the full relative case name/test.txt)
You can use Parameter expansion:
#!/bin/bash
path=/transfer/IN/name/test.txt
path1=${path%/*} # Remove everything from the last /.
path1=${path1##*/} # Remove everything up to the last /.
echo "$path1"

How to rename a bunch of files with a specific pattern

I want to rename the files in a directory which are named with this pattern:
string1-number.html
for example:
English-5.html
what I want to do is to rename the files like this:
string2-number.string3
for example:
Dictionary-5.en
How can I do this?
I used this script, but nothing happened:
echo "English-5.html" | sed 's%\({English}\).\(\.*\)\(html\)%dictionary\2\en%'
I would suggest using the mmv tool: http://linux.dsplabs.com.au/mmv-copy-append-link-move-multiple-files-under-linux-shell-bash-by-wildcard-patterns-p5/
With that you can do:
mmv *-*.html Dictionary-#2.en
echo "English-5.html" | sed 's%English\(-[0-9][0-9]*.\)html%dictionary\1en%'
Explanation:
I'm looking for English
followed by a dash, one or more numbers, and a dot -[0-9][0-9]*. (I surround this part with escaped parenthesis to make it a group (group 1)).
followed by html
In the replacement text, I use \1 to output the contents of group 1, as well as the changed text.
You have 2 errors: The {...} is not required, and you confused \. and .
\. matches a literal dot, while . matches a single character.
echo "English-5.html" |
sed 's%\(English\)\(.*\)\.\(html\)%dictionary\2.en%'
This answer shows some minor optimizations for sed commands already posted and shows how to actually rename the files (in the current folder):
for f in *; do mv "$f" $(echo "$f" |\
sed 's/^English-\([0-9]\+\)\.html$/dictionary-\1\.en/'); done

Batch rename of files with similar names

I have a series of files named like such:
file 1.jpeg
file 2.jpeg
file 3.jpeg
...
file 40.jpeg
I would like remove the space from all of their filenames without having to individually do it. I know its possible using something like: file{1,40}.jpeg or something like that but i can't remember and I don't even know how to search for it.
Thanks!
EDIT: linux
http://www.google.es/search?q=shell+rename+similar+files+in+a+directory
The first result is http://www.debian-administration.org/articles/150
Using the perl rename command [...] we can also, for example, strip spaces from filenames with this:
~$ rename 's/ //' *.jpeg
In other posts I've found this kind of commands that do not require perl:
for f in *; do mv "$f" `echo $f | tr --delete ' '`; done
I've not tried any of them.

Bash Scripting: Replace (or delete) string in a file if line starts with (or matches) another string

Assuming an ini-style file like this,
[Group]
Icon=xxx.ico
Title=An Image Editor
Description=Manipulates .ico, .png and .jpeg images
I want to replace/delete ".ico" ONLY in the line that starts with (or matches) "Icon="
I was trying this:
oldline="`cat "$file" | grep "Icon="`"
newline="`echo "$oldline" | tr ".ico" ".png"`"
cat "$oldfile" | tr "$oldline" "$newline" > $file
Then i realized that tr works completely different than i thought. Its NOT a tradicional "replace this for that" function. So i guess the correct way is using sed. But:
Ive never used sedbefore. No idea how it works. Is it overkill?
If the most indicated way is really using sed, given it is so powerful, is there any elegant way to accomplish this rather than this "fetch line -> modify line -> replace oldline for newline in file" approach?
Notes:
I cant replace ".ico" globally, i know that would be a LOT easier, i must restrict the replace to the Icon line, otherwise the Description line would be changed too.
Im new to shell scripting in Linux, so im looking not only to the solution itself, but also for the "proper" way to do it. Elegant, easy to read, conventional, etc
Thanks in advance!
Edit:
Thank you guys! Here is the final script, as a reference:
#! /bin/bash
# Fix the following WARNING in ~/.xsession-errors
# gnome-session[2035]: EggSMClient-WARNING: Desktop file '/home/xxx/.config/autostart/skype.desktop' has malformed Icon key 'skype.png'(should not include extension)
file="$HOME/.config/autostart/skype.desktop"
if [ -f "$file" ] ; then
if `cat "$file" | grep "Icon=" | grep -q ".png"` ; then
sed -i.bak '/^Icon=/s/\.png$//' "$file"
cp "$file" "$PWD"
cp "${file}.bak" "$PWD"
else
echo "Nothing to fix! (maybe fixed already?)"
fi
else
echo "Skype not installed (yet...)"
fi
MUCH sleeker than my original! The only thing i regret is that sed backup does not preserve original file timestamp. But i can live with that.
And, for the record, yes, ive created this script to fix an actual "bug" in Skype packaging.
Something like the following in sed should do what you need. First we check if the line starts with Icon= and if it does then we run the s command (i.e. substitute).
sed -i '/^Icon=/s/\.ico$/.png/' file
Edit: The sed script above can also be written like this:
/^Icon=/ { # Only run the following block when this matches
s/\.ico$/.png/ # Substitute '.ico' at the end of the line with '.png'
}
See this page for more details on how to restrict when commands are run.
sed is pretty easy to deal with. Here's one way:
sed 's/^\(Icon=.*\)\.ico$/\1.png/'
By default, sed works on every line in the file one at a time. The 's/.../.../' will do a regular expression match on the first argument and replace it with the second argument. The \1 stands for everything that matched the first group, which is demarcated by the parenthesis. You have to escape the parens with \.
The above works as part of a pipeline, but you can add an '-i' flag, like this
sed -i 's/^\(Icon=.*\)\.ico$/\1.png/' input.txt
to have it replace the file input.txt in place. Don't add that until you have tested your sed script a little.

Resources