Need to rename mulitiple files recursively using zmv - zsh

So I'm battling with a script at the moment. I'm using zsh. I've tried various combinations, but not coming right. Trying to change file names recursively. So basically I have a variable: file1.
What I'm trying to do is something like this:
zmv -W ${file1}/'**/*(test)*' ${file1}/'**/*red*'
This should change any file or folder in subdirectories recursively from test to red. Hence:
if $file1= /var/log then it should change:
/var/log/jump/greentest.txt to /var/log/jump/greenred.txt
also
/var/log/jump/1/1/test/test.xyz to /var/log/jump/1/1/red/red.xyz
Basically if I did a search:
ls **/*test* it would list all the files and folders recursively that had the word 'test' contained within them. With the zmv solution, I'd like to "find" those instances and change test to red.
How can I do this?

I hope you try these things first with -n....
Aside from this, the only part which looks wrong to me are the parenthesis around test. You introduce a new pattern variable for something which is not a wildcard, but your -W alreay implicitly introduces groups and references. Hence I would try it with
zmv -Wn $file1/'**/*test*' $file1/'**/*red*'
and if it works, remove the -n.

Related

Copy folders to new folder with different ending

I have a huge number of folders all with different names but same ending.
Like this:
blabla_ending1
Now I want to copy all those folders and give them another ending (ending2). I tried this but it did not work like I want to:
cp -r *_ending1 *_ending2
Somehow I need to specify that the second * depends on the first one. Maybe I am also unaware of the precise meaning of *. I know its very basic but I could not find any help yet.
I can't think of a simple command to achieve that. However, the following will achieve the desired result:
for path in *_ending1; do
newpath=`echo $path | sed 's/_ending1$/_ending2/'`
cp -r $path $newpath
done

Loop "paste" function over multiple files in the same folder

I'm trying to concatenate horizontally a number of files (1000) *.txt in a folder.
How can I loop over the files using the "paste" function?
NB: all the *.txt files are in the same directory.
Why loop? You can use wildcards.
paste *.txt > combined.txt
In general, it would be a question of just calling paste *.txt (and redirecting the output: paste *.txt > output.txt, as #zx did). Try it, but you'll be generating some enormously long lines. If paste can`t handle the line length you'll be generating, you'll have to reproduce its effect using a scripting language that has no line length limit, like perl or python.
Another possible sticking point is if your shell can't handle this many arguments in the expansion of the glob *.txt. Again, you can solve that with a script. It's easy to do so if that's your situation, let us know here.
PS. Given what paste does, looping is not going to do it for you: You (presumably) need the file contents side by side in the output, not one after the other.

How can I implement the command 'ls' with wildcard, '*'?

EDIT #1 : I'm under the limit that all arguments are enclosed in two quotes, so that shell do not expand any argument with * to the corresponding path.
EDIT #2 : In order to retrieve directories such as */*, ../*, and dirA/*/file.out, How should I use iteration loop or recursive call?
I have just learned about the function fnmatch(). But I don't know start place.
There are many possible cases. I'm confused dealing with these all cases.
For example, Let me assume that executable program is a.out.
$./a.out -l */*
$./a.out -l ../*
$./a.out -l [file_name] [directory_name]
/* Since I also have to implement ls command with no wildcard. */
What should I do? Any advice would be awesome.
Thank you in advance.
Your problem is : shell replaces wildcard caracter * with all of the filenames matching the pattern.
Solution:
If you do not want to use this feature of bash, just put quotation marks around your command line arguments.
Calling your program that way will have the original arguments, containing wildcards.
After this, you can list all the filenames with their paths. For example using some recursive algorithm. Then you can apply some matching to these path string. (when visiting it)
If you want to be a good unix citizen, the rule is Don't do filename globbing unless you are writing a shell.
You want to write an ls-like program? Don't do any wildcard expansion. Don't treat "*" specially. Just treat your argv as a list of filenames. If your program handles these cases:
./a.out file1
./a.out file1 file2 file3
Then it will also handle
./a.out file*
correctly because the shell will do the expansion and your program won't need to know about it. And besides that, it will handle this:
zsh% ./a.out **/file<40-185>~file<90-100>(.mm-30OL[1,2])
which in zsh expanded glob syntax means: expand file40 through file185, except for file90 through file100, include only the ones that have been modified in the last 30 minutes, and use only the largest 2 files in the resulting set.
fnmatch is never going to do anything like that. But these fancy globs can be used with any command that just takes a filename list and doesn't care where it came from.
When you're in a situation where you can't take a list of filenames from the command line, then consider using fnmatch. ls isn't one of those situations.

How to make the glob() function also match hidden dot files in Vim?

In a Linux or Mac environment, Vim’s glob() function doesn’t match dot files such as .vimrc or .hiddenfile. Is there a way to get it to match all files including hidden ones?
The command I’m using:
let s:BackupFiles = glob("~/.vimbackup/*")
I’ve even tried setting the mysterious {flag} parameter to 1, and yet it still doesn’t return the hidden files.
Update: Thanks ib! Here’s the result of what I’ve been working on: delete-old-backups.vim.
That is due to how the glob() function works: A single-star pattern
does not match hidden files by design. In most shells, the default
globbing style can be changed to do so (e.g., via shopt -s dotglob
in Bash), but it is not possible in Vim, unfortunately.
However, one has several possibilities to solve the problem still.
First and most obvious is to glob hidden and not hidden files
separately and then concatenate the results:
:let backupfiles = glob(&backupdir..'/*').."\n"..glob(&backupdir..'/.[^.]*')
(Be careful not to fetch the . and .. entries along with hidden files.)
Another, perhaps more convenient but less portable way is to use
the backtick expansion within the glob() call:
:let backupfiles = glob('`find '..&backupdir..' -maxdepth 1 -type f`')
This forces Vim to execute the command inside backticks to obtain
the list of files. The find shell command lists all files (-type f)
including the hidden ones, in the specified directory (-maxdepth 1
forbids recursion).

To restrict a node from `tree` by Tree or Git

How can you restrict a node from the command tree?
#1
I need to give a tree of my project files reqularly for my supervisor.
These files contain some third-party components which I do not want to show in the tree.
I have solved this problem this far by coping the project file to tmp, removing 3rd party-files and then running tree.
However, this procedure is becoming cumbersome.
I would like to get a better way to give tree of my files to my supervisor.
#2
I have the files which I want to show in Git so Git may solve this problem.
I run unsuccessfully
git ls-files --with-tree
You can specify the files you want to match and avoid using general patterns. From the tree manpage:
-P pattern
List only those files that match the wild-card pattern. Note: you must use the -a option to also consider those files beginning with a dot '.' for matching. Valid wildcard operators are '*' (any zero or more characters), '?' (any single character), '[...]' (any single character listed between brackets (optional - (dash) for character range may be used: ex: [A-Z]), and '[^...]' (any single character not listed in brackets) and '|' separates alternate patterns.
-I pattern
Do not list those files that match the wild-card pattern.
In your specific case, running
tree -I '3rd*'
should hide a directory called '3rd_party', including subdirs and files, while still allowing matches like 'party_3rd'. Obviously, other files and directories not containing '3rd' in the name will also display as normal. I've verified this behaviour with tree v1.5.2.1 on Linux.
You can put the third party tools is a separate subdirectory.
Then you only have to eliminate one node.
Instead of changing the tree command it might be better to place the 3rd-party files in a sibling folder of, not in a child folder of, your own source.

Resources