I need to rename multiple files by removing the multiple dates prefixing the files - linux

I accidently renamed all of my files by adding a prefix multiple times to each directory. I have tried the "rename" command and some peal scripting but I still can't resolve name changes. Any ideas on how to remove all the dates at once so that I just have directory?
Example
mv 2020-11-30-2020-11-30...2020-11-30-Documents Documents/

mv 2020-11-30-2020-11-30...2020-11-30-Documents Documents/
Assuming your filenames don't contain linebreak, quotes. or other special chars:
\ls -1|sed 's/.*-\(.*\)/mv "&" "\1"/'
You can check the output produced by the above command, if it looks good, pipe the output to |sh
NOTE: the backslash before ls is for ignoring your alias if you had ls alias.

These commands both worked:
ls -1 | sed 's/.*-\(.*\)/mv "&" "\1"/'
rename 's/2020-11-30-//g' 2020-11-30-*

Here is a solution which does not require the use of regex. Based on vimv and the multi-cursor edition in Vscode:
Both packages are shipped in most Linux distributions:
apt install vimv codium
Open a terminal and setup codium as your editor: export EDITOR="codium -w"
Browse the terminal in the appropriate folder and type vimv. Hit enter
Vscodium opens, and shows the list of files and folders
Add cursors where you want. Quoting from the doc:
You can add secondary cursors (rendered thinner) with Alt+Click. Another
common way to add more cursors is with Shift+Alt+Down or Shift+Alt+Up
that insert cursors below or above.
Delete whatever you want, save the file, and exit
The files and folders should be renamed accordingly
Checkout the website of vimv for more informations and screencasts

Related

How to replace double spaces with one space in filenames (also subdirectories) (CloudLinux Server release 6.10)

I want to replace double spaces with one space in the filenames of a lot of photos. These photos are located in directory /foto and it's subfolders. How to do this? For example "photo 1.jpg" needs to become "photo 1.jpg"
The best way is to use commandline, because it's on CloudLinux server. (and it is over 50GB of photos). I searched here on Stackoverflow, also Google to find the command I need. I guess rename is the one to use, or mv.
The only things I found were commands about replacing space and replacing other symbols, but not about double (multiple) spaces.
find -iname \*.* | rename -v "s/\s{2}/ /g"
This is the final command which helped me out. I used perl rename, see answer by Gilles
Use this, using Perl's rename :
rename 's/\s{2}/ /g' files*
Remove -n switch when the output looks good.
There are other tools with the same name which may or may not be able to do this, so be careful.
If you run the following command (GNU)
$ file "$(readlink -f "$(type -p rename)")"
and you have a result that contains Perl script, ASCII text executable and not containing ELF, then this seems to be the right tool =)
If not, to make it the default (usually already the case) on Debian and derivative like Ubuntu :
$ sudo update-alternatives --set rename /path/to/rename
Replace /path/to/rename to the path of your perl rename executable.
If you don't have this command, search your package manager to install it or do it manually (no deps...)
This tool was originally written by Larry Wall, the Perl's dad.

rsync - copy files with same name

I have some different files with the same name and I want to copy all of them to the destination which has a flat structure (no directories, just files), is there any way to append some text onto one of the file names so that both can be copied.
Need to use rsync because there are some files that I need to exclude from the copy.
For example:
dir1/file1.txt
dir1/dir2/file1.txt
both get copied, and in the destination there is:
file1.txt
file1.txt.txt
typically, when I want to do some complex name-mungling, I just write the list of files (with find dir1 >listfiles) and fix it with a text editor.
for example, s/^.*\/([^\/]+)$/cp \0 destination/\1/ converts a file like
dir1/file1.txt
dir1/dir2/file1.txt
to a script like:
cp dir1/file1.txt destination/file1.txt
cp dir1/dir2/file1.txt destination/file1.txt
then you could do something like cut -f 3 <listfiles | sort | uniq -d to find those with the same destination filename. then go back to the editor and fix those lines.
After a few minutes you get a full script for exactly the copy you want, without surprises because you can see each command and apply the best fix for each case.
As far as i know there is no default option in rsync to do that. But i guess that since you are copying files with the same name but from different directories, you are using
multiple rsync commands.
So, this gives you two options:
Create folders..
rsync -av /home/user1/file1 /media/foo/user1/file1
rsync -av /home/user2/file1 /media/foo/user2/file1
etc..
or rename the files with an id
rsync -av /home/user1/file1 /media/foo/parent_dir-file1
rsync -av /home/user2file1 /media/foo/parent_dir-file1
etc..
If you want to use the second solution you can build a simple script. As you are using rsync i suppose that you know the basics on GNU-Linux, so a simple bash script would be enough!
A basic ID is to get the parent folder name and add it as variable to the path of the rsync command. ( it won't always work )
IF you want to be sure of a good id you can for example set a counter and increment like
file1-1
file1-2
file1-3
But you will loose the track of its absolute path.
All the solutions can work, its up to you to choice the one that feed your needs!

renaming files with strange unicode names

Recently I downloaded some files from a website, but their names contain strange unicode characters, which my console doesn't show them properly. Now I want to rename these files to be able to use these files, but I get the following error:
mv: cannot stat`FILENAME': No such file or directory
But I am sure that these files exist.
I wonder how I can rename these files, properly.
Any ideas?
Using globbing characters (like ? or *): mv *some-typeable-and-unique-substring* ...
Using the tab-completion of your favourite shell: your start typing mv, then the beginning of the filename, then you press TAB, and then you can enter the second parameter.
If there are other files in that directory, you might have to move them to another directory to be able to use the tab-completion or the wildcards.

No tags file in GVim on some file but not on others

I just installed ctags via homebrew and appended the following line in my ~/.vimrc:
set tags=./tags,tags;$HOME
And then I ran /usr/local/bin/ctags -R . on some of my directories and opened some files stored in the directories, then some of those scripts succeeded in importing tags file but others didn't.
For example, I opened up test.py on my Python workspace, which I already run the above command in, and then I tried to put Ctrl+] on my GVim, it looks like successfully imported the tags file.
I also opened up hello.go located in ~/go/src/github.com/user/hello, in which I already executed the above ctags command, successfully imported the tags file. However, my test.rb file, which I just put on the Go's directory in order to do test purpose, didn't import the tags file correctly.
Also, when I executed the ctags command on ~/another_go_workspace/src, and then opened up the file located in ~/another_go_workspace/src/hello/hello.go, then the file didn't import the tags file... However, since I appended set tags=./tags,tags;$HOME on my ~/.vimrc, doesn't it automatically look for higher directories, right?
So what am I missing?
And if it doesn't import the tags file in higher directories, do I have to execute the ctag command on EVERY directory, i.e. on ~/go/src/soccer_analysis, ~/go/src/coffee, ~/go/src/utility, etc, etc... ?
Thanks.
Your value for the tags option is correct and your assumptions about its behaviour are correct too.
With your setting, set tags=./tags,tags;$HOME, Vim will search for a tags file in the directory of the current file first then for a tags file from the working directory upward to $HOME.
This allows you to generate a tags file at the root of your project and be sure that Vim will pick it up wherever you are in your project and whatever the working directory is.
With the following structure and your current settings:
project/
bar/
bar.js
foo/
foo.js
project.js
tags
Vim should find tags in all the following scenarios and their variants:
$ vim project.js
$ cd foo && vim foo.js
$ cd bar && vim bar.js
$ vim foo/foo.js
$ vim bar/bar.js
$ cd bar && vim bar.js ../project.js
Every time you add a new file to your project or write to an existing file, you must re-index your whole project. From what you wrote about the ruby file, it looks like you didn't run ctags after adding the file. Try this for a selection of files in your project: :echo tagfiles().
No, vim doesn't go up directories to find tags files. I recommend you start vim from the top level directory (where you generated your tags), then traverse to whatever file you want.
vim go/src/coffee
Vim is capable of navigating filesystems nicely with commands like :Explore.
EDIT: I was wrong, semicolon can be used to search upwards. See :help file-searching
Also, I noticed that you tried to add $HOME to your tags, which isn't going to work for a number of reasons.
Documentation (:help 'tags') says:
Filenames for the tag command, separated by spaces or commas.
Therefore:
The delimiter is incorrect
$HOME is going to be treated like a tags file
So the "correct" way of doing this would be:
set tags=./tags,tags,$HOME/tags
Even if you do that though, I don't think it's going to work. Tags files comprise primarily of 2 elements, a search pattern and a filename. If you generated the file from the top, all filenames will be relative to that directory.
So if you are deep down in some subdir, vim will try to open the file using the relative filepath from the top, starting at that subdir.
The problem may have been caused by a typo. I think
set tags=./tags,tags;$HOME
should be
set tags=./tags;,tags;$HOME

How to directly overwrite with 'unexpand' (spaces-to-tabs conversion)?

I'm trying to use something along the lines of
unexpand -t 4 *.php
but am unsure how to write this command to do what I want.
Weirdly,
unexpand -t 4 file.php > file.php
gives me an empty file. (i.e. overwriting file.php with nothing)
I can specify multiple files okay, but don't know how to then overwrite each file.
I could use my IDE, but there are ~67000 instances of to be replaced over 200 files, and this will take a while.
I expect that the answers to my question(s) will be standard unix fare, but I'm still learning...
You can very seldom use output redirection to replace the input. Replacing works with commands that support it internally (since they then do the basic steps themselves). From the shell level, it's far better to work in two steps, like so:
Do the operation on foo, creating foo.tmp
Move (rename) foo.tmp to foo, overwriting the original
This will be fast. It will require a bit more disk space, but if you do both steps before continuing to the next file, you will only need as much extra space as the largest single file, this should not be a problem.
Sketch script:
for a in *.php
do
unexpand -t 4 $a >$a-notab
mv $a-notab $a
done
You could do better (error-checking, and so on), but that is the basic outline.
Here's the command I used:
for p in $(find . -iname "*.js")
do
unexpand -t 4 $(dirname $p)/"$(basename $p)" > $(dirname $p)/"$(basename $p)-tab"
mv $(dirname $p)/"$(basename $p)-tab" $(dirname $p)/"$(basename $p)"
done
This version changes all files within the directory hierarchy rooted at the current working directory.
In my case, I only wanted to make this change to .js files; you can omit the iname clause from find if you wish, or use different args to cast your net differently.
My version wraps filenames in quotes, but it doesn't use quotes around 'interesting' directory names that appear in the paths of matching files.
To get it all on one line, add a semi after lines 1, 3, & 4.
This is potentially dangerous, so make a backup or use git before running the command. If you're using git, you can verify that only whitespace was changed with git diff -w.

Resources