Renaming files in subfolders using zmv - linux

Let's say I want to rename all the files inside all the subfolders of a folder from foo.txt to bar.txt using zmv.
I've tried zmv '**/foo.txt' 'bar.txt' but this creates bar.txt in the root folder. How can I keep the files in their corresponding subfolder?

You need to reference the directory part in the target. You can do that by putting the wildcards in parentheses and using $1 to refer to the part matched by the parenthetical group. The ** wildcard is a little special and requires that the parentheses are around **/, no more, no less.
zmv '(**/)foo.txt' '${1}bar.txt'
You can use the -w flag to have each wildcard automatically made into a parenthetical group.
zmv -w '**/foo.txt' '${1}bar.txt'
Or you can use the -W flag and use wildcards in the replacement text — with this flag, the wildcards in the replacement text are turned into $1, $2, etc.
zmv -W '**/foo.txt' '**/bar.txt'
Alternatively, you can use $f to refer to the source path.
zmv '**/foo.txt' '$f:r.txt'

Related

rename all files after extension

Is it possible to write a script to rename all files after the extension?
Example in the folder, there are :
hello.txt-123ahr
bye.txt-56athe
test.txt-98hg12
I want the output:
hello.txt
bye.txt
test.txt
If you just want to remove everything from the dash forwards, you can use Parameter expansion:
#!/bin/bash
for file in *.txt-* ; do
mv "$file" "${file%-*}"
done
Where ${file%-*} means "remove from $file everytning from the last dash". If you want to start from the first dash, use %%.
Note that you might overwrite some files if their leading parts are equivalent, e.g. hello.txt-123abc and hello.txt-456xyz.

Exclude directory when grepping with zsh globbing

I have some file structure which contains projects with build folders at various depths. I'm trying to use zsh (extended) globbing to exclude files in build folders.
I tried using the following command and many other variants:
grep "string" (^build/)#
I'm reading this as "Any folder that doesn't match build 0 or more times."
However I'm still getting results from folders such as:
./ProjectA/build/.../file.mi
./ProjectB/package/build/.../file2.mi
Any suggestions?
This should work:
grep string (^build/)#*(.)
Explanation:
^build: anything not named build
^build/: any directory not named build. It will not match any other file type
(^build/)#: any directory path consisting out of elements that are not named build. Again, this will not match a path where the last element is not a directory
(^build/)#*: Any path where all but the last element must not be named build. This will also list files. It also assumes that it would be ok, if the file itself were named build. If that is not the case you have to use (^build/)#^build
(^build/)#*(.): Same as before, but restricted to only match normal files by the glob qualifier (.)
I think you don't need to involve the shell for that task; grep comes with its own file-globber. From manpage:
--exclude-dir=GLOB
Skip any command-line directory with a name suffix that matches the pattern GLOB. When searching recursively, skip any subdirectory whose
base name matches GLOB. Ignore any redundant trailing slashes in GLOB.
So something like this should get the job done for you:
grep -R "string" --exclude-dir='build'
That filter will leave out subdirectories called exactly "build"; if you want to filter out directories that contain the string "build" (such as "build2" or "test-build") then use globbing inside the exclusion pattern:
grep -R "string" --exclude-dir='*build*'
For completeness' sake, I also include here how to do the same thing with two popular grep alternatives that I'm more or less familiar with:
The Silver Searcher: ag -G '^((?!build).)*$' string
Ripgrep: rg -g '!build'
Using the glob qualifier e did the trick for me, both for 'grep' and 'ls':
grep -s "string" **/*(e[' [[ ! `echo "$REPLY" | grep "build/" ` ]]'])

Linux : Copy Multiple files and remove it's extension

I have got a directory containing files of type *.cpp.So i would like to copy each file in the directory and to paste it in the same directory by using
cp -a *.cpp
with an option to remove the .cpp while pasting.Is it possible ?
Here is a simple bash script. This script assumes that the file name only contains one "." character and splits based on that.
#!/bin/sh
for f in *.cpp; do
#This line splits the file name on the delimiter "."
baseName=`echo $f | cut -d "." -f 1`
newExtension=".new"
cp $f $baseName$newExtension
done
You can do this just by means of bash parameter extension, as mentioned in the bash manual:
${parameter%%word}
Remove matching suffix pattern. The word is expanded to produce
a pattern just as in pathname expansion. If the pattern matches
a trailing portion of the expanded value of parameter, then the
result of the expansion is the expanded value of parameter with
the shortest matching pattern (the ``%'' case) or the longest
matching pattern (the ``%%'' case) deleted.
...
for i in *.cpp
do
cp -a $i ${i%%.cpp}
done
Can use rename, optionally with -f to force rewrite existing files.
rename -f 's/\.ext$//' *.ext
To preview actions, but don't change files, use -n switch (No action).
This is not copy but move :-(

grep recursively for a specific file type on Linux

Can we search a term (eg. "onblur") recursively in some folders only in specific files (html files)?
grep -Rin "onblur" *.html
This returns nothing. But,
grep -Rin "onblur" .
returns "onblur" search result from all available files, like in text(".txt"), .mako, .jinja etc.
Consider checking this answer and that one.
Also this might help you: grep certain file types recursively | commandlinefu.com.
The command is:
grep -r --include="*.[ch]" pattern .
And in your case it is:
grep -r --include="*.html" "onblur" .
grep -r --include "*.html" onblur .
Got it from :
How do I grep recursively?
You might also like ag 'the silver searcher' -
ag --html onblur
it searches by regexp and is recursive in the current directory by default, and has predefined sets of extensions to search - in this case --html maps to .htm, .html, .shtml, .xhtml. Also ignores binary files, prints filenames, line numbers, and colorizes output by default.
Some options -
-Q --literal
Do not parse PATTERN as a regular expression. Try to match it literally.
-S --smart-case
Match case-sensitively if there are any uppercase letters in PATTERN,
case-insensitively otherwise. Enabled by default.
-t --all-text
Search all text files. This doesn't include hidden files.
--hidden
Search hidden files. This option obeys ignored files.
For the list of supported filetypes run ag --list-file-types.
The only thing it seems to lack is being able to specify a filetype with an extension, in which case you need to fall back on grep with --include.
To be able to grep only from .py files by typing grepy mystring I added the following line to my bashrc:
alias grepy='grep -r --include="*.py"'
Also note that grep accepts The following:
grep mystring *.html
for .html search in current folder
grep mystring */*.html
for recursive search (excluding any file in current dir!).
grep mystring .*/*/*.html
for recursive search (all files in current dir and all files in subdirs)
Have a look at this answer instead, to a similar question: grep, but only certain file extensions
This worked for me. In your case just type the following:
grep -inr "onblur" --include \*.html ./
consider that
grep: command
-r: recursively
-i: ignore-case
-n: each output line is preceded by its relative line number in the file
--include \*.html: escape with \ just in case you have a directory with asterisks in the filenames
./: start at current directory.

Search and replace text in all files of a linux directory

I have a website directory where I need to change all hardcoded links from one domain to another. Looking for a single (grep? sed?) bash command that will allow me to change all occurrences of text in all files in the directory?
The following will do it:
sed -i 's/old_link/new_link/g' file...
Don't forget to escape any slashes, dots, and any other regex special chars in the link addresses with a backslash.
Also, try:
perl -p -i -e <regex> <folder>

Resources