unix command 'mv' failure - file-io

I am using move command mv -f $file1 $file2 to move a file from source directory to a destination directory. I am getting a failure message as:
mv: cannot create regular file $file2:File exists
Could you let me know on the reason for such failures from move command?
Are there any ways to solve this error?

This is caused by race condition. Your were running multiple mv in your scripts.

Does that file really exist? If it exists, and you are SURE that you want to overwrite it, add the -f flag, which will force the command to continue;
mv -f file1 file2

This error can be caused by a privileges conflict and occasionally by using illegal characters in the file name. Make sure there are no unusual special characters in the file's name and verify that there is not already a file with the same name in the directory that the file is being moved to. You might need to use ls -l from above target directory to see if the privileges settings will allow you to read/write to the directory.

Related

Muttrc: how to source a file in muttrc's directory

I have a muttrc file which sources a secondary file mutt-secrets which resides in its same directory. But I have what appear to be two conflicting needs:
Be free to reference the muttrc file from any working directory
Be free to move it (and mutt-secrets) without having to edit muttrc to change the source path for mutt-secrets
At present, the first line of my muttrc says: source mutt-secrets. That works fine when I run mutt from within the directory where the two file reside, but if I run mutt from elsewhere and reference muttrc with a -F flag, then mutt can find muttrc, but muttrc can't find mutt-secrets.
How can I solve this?
Use absolute paths. For example:
source ~/.mutt/mutt-secrets
TL;DR one-line solution:
source `lsof -c mutt -Fn | grep '/muttrc$' | sed 's|^n||; s|/muttrc$||;'`/mutt-secrets
or, if you want to reuse the muttrc directory, you can save it to a custom variable:
set my_muttrc_dir = `lsof -c mutt -Fn | grep '/muttrc$' | sed 's|^n||; s|/muttrc$||'`
source $my_muttrc_dir/mutt-secrets
If you want to see the output of the command when you launch mutt, you can put this line in your muttrc:
echo `lsof -c mutt -Fn | grep '/muttrc$' | sed 's|^n||; s|/muttrc$||'`
Assumptions: the Mutt process is called mutt and the Mutt's initialization file is called muttrc. Furthermore, you could get in trouble if you have more than one Mutt instance running (for example if you launch in parallel two or more Mutt instances with different initialization files, because the command may select the wrong path).
Explanation
The idea is to look for muttrc full path in the list of open files by Mutt. We can get this list using lsof command (it has to be installed in your system), then extract the full path by parsing the lsof output with grep and sed commands.
This approach is viable because Mutt's initialization files support the use of external command's output with backticks (``). When Mutt encounter and execute our command enclosed in backticks (``), it is in the process of reading the muttrc file, so the muttrc file appears in the list of currently open files by Mutt. This enables us to use the lsof command.
lsof parameters
-c mutt: list open files of process named mutt;
-Fn: for each element, print only the name (it is the path in our case). Because of lsof output format, the path will be prefixed with the character n.
grep and sed
We use grep to select the line which contains muttrc file path, assuming the filename is exactly muttrc. Then we clean the lsof output with sed by both removing the n character at the beginning of the line and the /muttrc string from the end of the line. This way we get the path of the directory containing the muttrc file.
There is a cleaner solution?
Mutt expands relative paths inside initialization files from its current working directory, i.e. from the directory you launch Mutt. It supports a mechanism that allows path's expansion relatives to something different, but the "initialization file directory" or something similar are not available. See here.
I neither found a way to get the -F <path> option you pass to the mutt command inside the initialization file.
References
backticks in Mutt's initialization file;
current directory;
_mutt_buffer_expand_path, source code
source_rc, source code
source_rc call, source code
Tested with: Mutt 2.0.5, lsof 4.93.2, GNU grep 3.7, GNU sed 4.7.

Check files have execute permission using CMake

I have a CMakeLists.txt that requires certain input files to have write permissions, otherwise the make process fails with a rather obscure "Permission denied Error 126" message. The page here describes the usage, with the key points being:
In order to make this cfg file usable it must be executable, so lets use the following command to make it executable
chmod a+x cfg/Tutorials.cfg
Next we need to add the following lines to our CMakeLists.txt. For Groovy and above
generate_dynamic_reconfigure_options(
cfg/Tutorials.cfg
#...
)
add_dependencies(example_node ${PROJECT_NAME}_gencfg)
How would I alter the above snippet so I could do something sensible if I forget to run chmod on cfg/Tutorials.cfg thus it is not executable?
As described in the key points, you must make the file executable by chmod 0555 but you have to be cautious when doing this. By chmod 0555, even the owner of the file, other than root, is denied write privileges. I recommend using 0775 or something else better as it grants read and write permission.

tar trying to open instead of create an archive

I'm trying to run a command like this to back up my public directory:
tar -zcvf backups/2014-09-09-public_html.tar.gz public_html -C home/path
My understanding is that this is supposed to create and an archive with the compressed contents of my public directory. But I'm getting the following errors:
tar (child): backups/2014-09-09-public_html.tar.gz: Cannot open: No such file or directory
tar (child): Error is not recoverable: exiting now
tar: Child returned status 2
This has me confused because I want it to create the file, not open it. I've used similar commands in other projects without problems, so I'm not sure what the problem could be here. What could I be doing wrong?
When you create a file, you actually open it in write mode, even if it does not yet exist (read man 3 open to further understand how this works on *nix).
Are you sure you have write permissions for the destination where you're trying to compress? Can you touch(1) that location?
Well, I finally got it working by putting -C /home/path at the beginning and using the absolute path for the archive name instead of the relative path:
tar -C /home/path -zcvf /home/path/backups/2014-09-09-public_html.tar.gz public_html
I still don't understand why I need to specify the absolute path for the archive name since I've always used the relative path in other projects. I guess maybe it's a difference in how this server is set up or something?

Backup file folder in correct way

My situation is I only have execute permission from some folder:
Lets say, I would like to backup entire folder and exclude some folder and files with exclude.txt
Here is path I would like to backup:
/pdf/data/pdfnew/2014
And I only have permission to execute from this folder (main):
/pdf/data/pdfnew/2014/public/main
I put exclude.txt in same folder which I can execute the command (main)
I execute this command in (main folder):
tar -cjvf -X exclude.txt 2014.tar.bz2 /pdf/data/pdfnew/2014
The result is it still included folder that I dont want to backup.
Is there a correct way doing this?
Do you have a user/home directory on that server? You should, so you should just place exclude.txt in your user/homedirectory on that server & run it like this from that directory:
tar -cjvf -X ~/exclude.txt ~/2014.tar.bz2 /pdf/data/pdfnew/2014
The ~/ is a shorthand for your user/home directory so in this case it is explicitly stating, “Read exclude.txt from the user/home directory & write ~/2014.tar.bz2 to the user/home directory.
But you also ask this:
Is there a correct way doing this?
There is never one canonical best way of doing something like this. It is all based on your final/end goal. Nothing more. Nothing less. That said, if I were you I would do it like this instead using the -C option:
tar -cjvf -X ~/exclude.txt ~/2014.tar.bz2 -C /pdf/data/pdfnew/ 2014
The uppercase -C option allows tar to internally change the working directory to /pdf/data/pdfnew/ so you can then create an archive of 2014 without having to have the whole directory tree retained in the backup. I find this is easier to work with because many times I want to backup the contents of a directory but have no use to retain the parent structure. That way the archive is more like a traditional ZIP archive which I find is easer to understand & work with.

zsh survive glob failure

I have checked out a project, the project contains a .gitignore file.
The contents of this file are like so
vx1% head .gitignore
./deps
/*.exe
/*.la
/.auto
.libs
ChangeLog
Makefile
Makefile.in
aclocal.m4
autom4te.cache
I want to
read the file line by line
for each line read, list the actual files that are being ignored
finally I want to tweak the script to delete those files
The reason for wanting to do this - is that I don't trust the project Makefile to fully clean up it's generated files.
Notes
As you can see, the .gitignore uses some globs that I need to modify before running the commands, otherwise the glob will resolve to my root directory.
What I already know
To dynamically evaluate an arbitrary string as a glob pattern
DYN="*.c"
print $~DYN
To strip the leading /, if it exists
DYN="/*.c"
print ${~DYN/#//}
What I've got
cat .gitignore | while read i; do echo $i ; print ${~i/#//} ; done
The problem
The first glob failure that this loop encounters, it terminates with error
zsh: no matches found: *.exe
What I want
The 'script' should keep going through each line of the file, trying each line in turn.
I answered this myself, answer is below
Found the answer on the zsh mailing list, in typical Zsh fashion - it's very simple when you know how, and impossible otherwise.
print *.nosuchextension(N)
The (N) glob parameter prevents raising an error on match failure.