How to rename file with bash by adding first symbol - dot? - bash

I would like to rename my file from myscript.js to .myscript.js. How can I do it with bash? I've tried different options like mv myscript.js \.*, but it doesn't work. I've tried to experiment by adding non-dot symbol like - mv myscript.js m*, but now I don't even know where my file is (of course, I have a copy ;).

You're trying too hard.
mv myscript.js .myscript.js

Brace expansion
mv {,.}myscript.js

You can use rename utility to rename all *.js file by placing a dot before them:
rename 's/(.+\.js)/.$1/' *.js
Or in pure BASH use this for loop:
for i in *.js; do mv "$i" ".$i"; done

Don't use patterns as the target of mv (or cp for that matter). The command won't do what you want or expect, most of the time: Bash will expand the pattern at the moment when you run the command, using the file names as they were before your command was executed. So .* matches nothing (since the file doesn't exist, yet) and m* will match any file or folder which starts with m. Since you didn't get an error, chances are that the last match was a folder.
There is no way to access the previous parameter of the current command. If you want to avoid typing too much, then use Tab for both file names (so you end up with mv myscript.js myscript.js) and then use Ctrl+Left and Ctrl+Right to move quickly to the start of the second argument to insert the missing ..
You can access the parameters of the previous command, though. But that's not a feature of BASH - it's a feature of readline.

Related

Bash command line: Is there a way to use the first parameter's value as part of second parameter?

I frequently make temporary backups of files by making a file with nearly the same name, e.g.:
cp /some/long/path/code.php /some/long/path/code.phpcode.php.WIP_desc
Is there some way to shorten this without creating an alias?
You can use brace expansion in bash:
cp /some/long/path/code.php{,.WIP_desc}
Create a file named makeFileBackup with this content
#!/usr/bin/env bash
cp "$1" "$1.WIP_desc"
and then run chmod +x makeFileBackup.
Now you can use it as /path/to/makeFileBackup some_file.
As suggested in a command, you might want to use the above program without having to specify /path/to/ in front of it. Two general approaches are possible:
move makeFileBackup to, or create a link to it in a location that's already in PATH;
add to PATH the location where makeFileBackup is; in this case, you probably still don't want it to be in /home/yourusername but in its own directory.
Is creating a variable ok?
p=/some/long/path
cp $p/code.php $p/code.phpcode.php.WIP_desc
Double quote the expansion if p may contain white space.

Rename files using rename command in bash shell

I have read other similar questions on the forum and I can't understand why the command I tried doesn't work.
I have a list of files named in the form aaaa_100_aaaa.csv, aaaa_100_aaab.csv, aaaa_100_aaac.csv and so on, and I want to replace "100" with "200".
I'm running bash in Windows PowerShell WSL. I tried with this command
rename 's/420/410/g' *.csv
I found the same expression in many answers on the forum but it doesn't work. I got the error message
mv: target 'aaaa_100_aaaa.csv' is not a directory.
Given that the error message starts with mv:, and therefore apparently is produced by the mv ("move") command, I'm willing to bet that your bash has been configured to treat rename as an alternative name for mv. So you aren't really running the rename command at all.
To check this, run type rename. It will probably tell you that rename is an alias or a shell function, not the reference to the /usr/bin/rename executable that you expected.
You can get around this by using the full pathname to invoke rename:
/usr/bin/rename 's/100/200/g' *.csv
or by writing a backslash in front of rename to tell bash to skip any special handling of the command name:
\rename 's/100/200/g' *.csv
Of course if you're going to want to use the real rename often then remembering to do that every time will be annoying. You could unalias rename but that only fixes it in the current shell.
The long-term solution is to prevent bash from treating rename as a shortcut. To do that you'll first have to find out where the alias or function is being defined, and then remove that definition. It's probably in your $HOME/.bashrc or $HOME/.bash_profile file. If it's not there then something like grep rename $HOME/.* should find it. If that doesn't find it then it might be in a system startup file that you can't (or don't want to) edit, and in that case you could get rid of it by adding unalias rename to your .bashrc or .bash_profile.

How to create one output file for each file passed to a loop in bash?

I have a file that I pass to a bash command that will create an output in a loop like so:
for file in /file/list/*
do
command
done
I wish to save the output that would have gone to standard out of each loop to a text file in my working directory. Currently I am trying this:
for file in /file/list/*
do
command | tee "$file_command output.txt"
done
What I expect to see are new files created in my current directory titled file1.txt_commandoutput.txt, file2.txt_commandoutput.txt, etc. The output of the command should be saved as a different file for each file. However I get only one file created and it's called ".txt" and can't be opened by any standard software on Mac. I am new to bash scripting, so help would be much appreciated!
Thanks.
Your problem comes from the variable name you're using:
"$file_command_output.txt" looks for a variable named file_command_output (the dot cannot be in the variable name, but the alphanumerical characters and the underscore all can).
What you're looking for is "${file}_command_output.txt" to make the variable name more explicit.
You have two issues in your script.
First, the wrong parameter/variable is expanded (file_command instead of file) because it's followed by a character that can be interpreted as part of the name (the underscore, _). To fix it, enclose the parameter name in braces, like this: ${file}_command (see Shell Parameter Expansion in bash manual).
Second, even with fixed variable name expansion, the file won't be created in your working directory, because the file holds an absolute pathname (/file/list/name). To fix it, you'll have to strip the directory from the pathname. You can do that with either basename command, or even better with a modified shell parameter expansion that will strip the longest matching prefix, like this: ${file##*/} (again, see Shell Parameter Expansion, section on ${parameter##word}).
All put together, your script now looks like:
#!/bin/bash
for file in /file/list/*
do
command | tee "${file##*/}_command output.txt"
done
Also, to just save the command output to a file, without printing it in terminal, you can use a simple redirection, instead of tee, like this: command > "${file##*/}_com...".
If you are not aware of xargs, try this:
$ ls
file
$ cat > file
one
two
three
$ while read this; do touch $this; done < ./file
$ ls
file one three two

Batch renaming files in OSX terminal

I'm trying to rename files e.g. screen-0001.tif to 0001.tif using the approach in this SO question:
for file in *.tif
do
echo mv "$file" "${screen-/file}"
done
fails to change anything. Grateful for an idea where I'm going wrong.
The easier, IMHO, way to do this is using Perl's rename script. Here I am using it with --dry-run so it just tells you what it would do, rather than actually doing anything. You would just remove --dry-run if/when you are happy with the command:
rename --dry-run 's/screen-//' *tif
'screen-001.tif' would be renamed to '001.tif'
'screen-002.tif' would be renamed to '002.tif'
'screen-003.tif' would be renamed to '003.tif'
'screen-004.tif' would be renamed to '004.tif'
It has the added benefit that it will not overwrite any files that happen to come out to the same name. So, if you had files:
screen-001.tif
0screen-01.tif
And you did this, you would get:
rename 's/screen-//' *tif
'screen-001.tif' not renamed: '001.tif' already exists
rename is easily installed using Homebrew, using:
brew install rename
Two things:
You're echoing the commands and not actually executing them. I will do this when I do massive renames just to make sure that the command works correctly. I can redirect the output to a file, and then use that file as a shell script.
The substitution is wrong. There are two ways:
Left most filter ${file#screen-}.
Substitution: ${file/screen/}
The name of the environment variable always goes first. Then the pattern type, then the pattern
Here's how I would do this:
$ for file in *.tif
> do
> echo "mv '$file' '${file#screen-}'"
> done | tee mymove.sh # Build a shell script
$ vi mymove.sh # Examine the shell script and make sure everything is correct
$ bash mymove.sh # If all is good, execute the shell script.

How do I git mv files with ext *.css.scss to *.scss using bash?

I've run into this a few times and I'm curious about automating it. If I want to move a bunch of files matching a pattern to a slightly different pattern, how would I do it?
More specifically, If I want to git mv the following files
fileA.css.scss
fileB.css.scss
...
to
fileA.scss
fileA.scss
...
How would you do it?
I would write something like:
for file in *.css.scss ; do
mv "$file" "${file%.css.scss}.scss"
done
(Note: I'm not sure of the right arguments for git mv, so I just demonstrated using mv, I hope that's O.K.)
For information on the ${parameter%word} notation, see ยง3.5.3 Shell Parameter Expansion in the Bash Reference Manual.

Resources