How can I delete a directory like this "-work.lib++" in linux? [duplicate] - linux

Somehow, at some point, I accidentally created a file in my home directory named '-s'. It is about 500 kb and I have no idea if it contains important data or not. I cannot figure out any way to do anything with this file, because every command I use to try to view, copy, or move it interprets the filename as an argument.
I've tried putting it in quotes, escaping it with a backslash, a combination of the two, nothing seems to work.
Also, when I first posed this question to my coworkers, we puzzled over it for a while until someone finally overheard and asked "why don't you just rename it?" After I explained to him that cp and mv both think the filename is an argument so it doesn't work, he said "no, not from the command line, do it from Gnome." I sheepishly followed his advice, and it worked. HOWEVER I'm still interested in how you would solve this dilemma if you didn't have a window manager and the command line was the only option.

You can refer to it either using ./-filename or some command will allow you to put it after double dash:
rm -- -filename

You can get rid of it with:
rm ./-s
The rm command (at least under Ubuntu 10.04) even tells you such:
pax#pax-desktop:~$ rm -w
rm: invalid option -- 'w'
Try `rm ./-w' to remove the file `-w'.
Try `rm --help' for more information.
The reason that works is because rm doesn't think it's an option (since it doesn't start with -) but it's still referring to the specific file in the current directory.

You could use --, e.g.:
rm -- -file

Just for fun you could also use/abuse find.
find . -name "-s" -delete
or
find . -name "-s" -exec cat {} \;

besides using rm, if you know a language, you can also use them. They are not affected by such shell warts.
Ruby(1.9+)
$ ruby -rfileutils -e 'FileUtils.rm("-s")'
or
$ ruby -e 'File.unlink("-s")'

Related

How to quickly rename my files on macOS or linux from CLI?

Here're my source files.
e2f9eb91-645f-408a-9241-66490b61a617_file-module-1.txt
d20f06a8-4de1-4da0-8175-93e9b2d81c42_file-module-2.txt
6740a19f-e1a0-43da-9a01-9e873238360e_file-module-3.txt
.
.
.
I need to figure it out a way to rename all the files to remove the first 36 characters up to _file or replacing as something else. I am expecting all the files are as below.
_file-module-1.txt or Yong_file-module-1.txt
_file-module-2.txt or Yong_file-module-2.txt
_file-module-3.txt or Yong_file-module-3.txt
.
.
.
Thanks in advance!
You can use rename like this:
rename --dry-run 's/.*_file/Yong_file/' *.txt
If you are on macOS, you can install rename with homebrew:
brew install rename
If you use mac, you can simply try this via UI:
https://support.apple.com/en-us/guide/mac-help/mchlp1144/mac
Or if you want to try those work via CLI:
https://www.howtogeek.com/423214/how-to-use-the-rename-command-on-linux/
(read from Renaming Multiple Files with mv)
This might help also; sed commands of linux:
https://www.geeksforgeeks.org/sed-command-in-linux-unix-with-examples/
and another stackoverflow article: bash substitute first character in every line
Easiest way to do this would be to use a combination of find, sed and xargs.
find . -name '*.txt' | sed 'p;s/.*_file/Yong_file/' | xargs -n2 mv
This finds text files in the current working directory, echoes the original file name (p) and then a modified name (s/.*_file/Yong_file/) and feeds it all to mv in pairs (xargs -n2).
If you would use zsh, you could do a
autoload zmv # Because zmv is not active by default
zmv '????????????????????????????????????(*module*txt)' '_$1'
Since you want to use bash, you could steal it from zsh and use it within bash like this:
zsh -c "autoload zmv; zmv '????????????????????????????????????(*module*txt)' '_$1'"
(These should be 36 question marks; better you count them again instead of blindly copying this code).

Converting .aiff to .wav in SoX

I have multiple files in a directory that are in .aiff format, and I would like to convert them to .wav using SoX. I have tried the code on this website, which is as follows
theFiles = `/Users/me/RainbowAiff/*.aiff`;
for eachFile in $theFiles; do v1=${eachFile%*.aiff};
oldFile="$v1.aiff"; newFile = "$v1.wav";
echo oldFile $oldFile; echo newFile $newFile; sox $oldFile $newFile; done
and this website, which is as follows
for i in `/Users/me/RainbowAiff/ *.aiff`; do echo -e "$i"; sox $i $i.wav; echo -e "$i.wav"; done;
but I get an error message in both instances that says "cannot execute binary file". What could be the source of this error?
Incompatible binary files cause this error, see this question.
If the outputs from file sox and uname -a commands tell that there is a discrepancy between the binary file and your operating system, i.e., x86 vs. ARM, you need to find the correct binary for SoX. Although there is no SoX release since 2015, check this and this to find a version that is compatible with your system.
The problem is also related to the file attributes of the sox. In order to give it the executable attribute, simply go to the folder where sox is located and run chmod +x sox command (you need root access first).
The two snippets you linked to looks a little sketchy to me with their use of ls and echo.
echo -e might in fact be what gave you the syntax error, as OSX (BSD) echo does not have an -e option. (type man echo into the terminal to see).
I took the liberty of assembling an alternative one-liner, based around find and its -exec option.
find -E . -maxdepth 1 -iregex '.*\.(aif|aiff)' -exec bash -c '$0 "$1" "${1%.*}.wav"' sox {} \;
To explain it:
find: can find about anything
-E: enables extended regex*
.: starts in current working directory. Can be replaced with relative or absolute path
-maxdepth 1: looks only in the first directory layer. Replace 1 with 2 to also find files within folders, with 3 to also find files within folders within folders …
Removing this option will enable full recursion (find files all the way down)
-iregex: use case-insensitive regular expressions
'.*\.(aif|aiff)': match anything that starts with anything (.) at any length (*), followed by a period (\.) and the strings 'aif' or 'aiff' (or 'AIF', 'AIFF', 'aiFF' …) ((aif|aiff))
-exec bash -c : execute the following in a non-interactive bash shell
Right around here it gets a bit more complicated
'$0 "$1" "${1%.*}.wav"': this is the call to be run inside the bash shell. $0 will expand to the program name. "$1" will expand to the first (and in this case, only) argument, enclosed in double quotes in case of white-spaces. "${1%.*}.wav" will also expand to the first argument, except it will strip away the last period and everything after, before tagging on '.wav' at the end. Effectively replacing the file extension.
sox {}: these are the arguments passed to the shell call. The first (sox) is the program we want to use, referred to as $0 within the call. The second ({}) is whatever file find has found, and referred to as $1 within the shell call
That's quite a mouthful and I'm no expert, so there might be some mistakes in what I've written, though the general outline should be solid.
*This is OSX specific, a less pretty but more portable option would be:
find . -maxdepth 1 \( -iname "*.aif" -o -iname "*.aiff" \) -exec bash -c '$0 "$1" "${1%.*}.wav"' sox {} \;

Encoding filenames with encfsctl which begin with a "-" [duplicate]

Somehow, at some point, I accidentally created a file in my home directory named '-s'. It is about 500 kb and I have no idea if it contains important data or not. I cannot figure out any way to do anything with this file, because every command I use to try to view, copy, or move it interprets the filename as an argument.
I've tried putting it in quotes, escaping it with a backslash, a combination of the two, nothing seems to work.
Also, when I first posed this question to my coworkers, we puzzled over it for a while until someone finally overheard and asked "why don't you just rename it?" After I explained to him that cp and mv both think the filename is an argument so it doesn't work, he said "no, not from the command line, do it from Gnome." I sheepishly followed his advice, and it worked. HOWEVER I'm still interested in how you would solve this dilemma if you didn't have a window manager and the command line was the only option.
You can refer to it either using ./-filename or some command will allow you to put it after double dash:
rm -- -filename
You can get rid of it with:
rm ./-s
The rm command (at least under Ubuntu 10.04) even tells you such:
pax#pax-desktop:~$ rm -w
rm: invalid option -- 'w'
Try `rm ./-w' to remove the file `-w'.
Try `rm --help' for more information.
The reason that works is because rm doesn't think it's an option (since it doesn't start with -) but it's still referring to the specific file in the current directory.
You could use --, e.g.:
rm -- -file
Just for fun you could also use/abuse find.
find . -name "-s" -delete
or
find . -name "-s" -exec cat {} \;
besides using rm, if you know a language, you can also use them. They are not affected by such shell warts.
Ruby(1.9+)
$ ruby -rfileutils -e 'FileUtils.rm("-s")'
or
$ ruby -e 'File.unlink("-s")'

questions on Linux command "find -exec {}"

I tried to update a file in subversion. I need to add a line in makefile, in order to build up the revised version of code. Here is the command I tried to find the place in make file.
find . -name "*ake*" -exec grep filename {} /dev/null \;
It works. But my questions are:
1. What is the "\;" for? If I change it, there will be error message.
2 The /dev/null didn't change the results. I know this is the device where dispose all the "garbage information". But I still don't quite understand it in this situation.
Thanks in advance!
The \; indicates the end of the command to be executed by find. The \ is required to stop the shell interpreting the ; itself. From man find:
-exec command ;
Execute command; true if 0 status is returned. All following
arguments to find are taken to be arguments to the command until an
argument consisting of ‘;’ is encountered.
The /dev/null is a clever trick that took me a while to figure out. If grep is passed more than one filename it prints the containing filename before each match. /dev/null acts as an empty file containing no matches, but makes grep think it is always passed more then one filename. A much clearer alternative suggested by richard would be to use grep's -H option:
-H, --with-filename
Print the filename for each match. This is the default when there
is more than one file to search.

How to delete multiple files at once in Bash on Linux?

I have this list of files on a Linux server:
abc.log.2012-03-14
abc.log.2012-03-27
abc.log.2012-03-28
abc.log.2012-03-29
abc.log.2012-03-30
abc.log.2012-04-02
abc.log.2012-04-04
abc.log.2012-04-05
abc.log.2012-04-09
abc.log.2012-04-10
I've been deleting selected log files one by one, using the command rm -rf see below:
rm -rf abc.log.2012-03-14
rm -rf abc.log.2012-03-27
rm -rf abc.log.2012-03-28
Is there another way, so that I can delete the selected files at once?
Bash supports all sorts of wildcards and expansions.
Your exact case would be handled by brace expansion, like so:
$ rm -rf abc.log.2012-03-{14,27,28}
The above would expand to a single command with all three arguments, and be equivalent to typing:
$ rm -rf abc.log.2012-03-14 abc.log.2012-03-27 abc.log.2012-03-28
It's important to note that this expansion is done by the shell, before rm is even loaded.
Use a wildcard (*) to match multiple files.
For example, the command below will delete all files with names beginning with abc.log.2012-03-.
rm -f abc.log.2012-03-*
I'd recommend running ls abc.log.2012-03-* to list the files so that you can see what you are going to delete before running the rm command.
For more details see the Bash man page on filename expansion.
If you want to delete all files whose names match a particular form, a wildcard (glob pattern) is the most straightforward solution. Some examples:
$ rm -f abc.log.* # Remove them all
$ rm -f abc.log.2012* # Remove all logs from 2012
$ rm -f abc.log.2012-0[123]* # Remove all files from the first quarter of 2012
Regular expressions are more powerful than wildcards; you can feed the output of grep to rm -f. For example, if some of the file names start with "abc.log" and some with "ABC.log", grep lets you do a case-insensitive match:
$ rm -f $(ls | grep -i '^abc\.log\.')
This will cause problems if any of the file names contain funny characters, including spaces. Be careful.
When I do this, I run the ls | grep ... command first and check that it produces the output I want -- especially if I'm using rm -f:
$ ls | grep -i '^abc\.log\.'
(check that the list is correct)
$ rm -f $(!!)
where !! expands to the previous command. Or I can type up-arrow or Ctrl-P and edit the previous line to add the rm -f command.
This assumes you're using the bash shell. Some other shells, particularly csh and tcsh and some older sh-derived shells, may not support the $(...) syntax. You can use the equivalent backtick syntax:
$ rm -f `ls | grep -i '^abc\.log\.'`
The $(...) syntax is easier to read, and if you're really ambitious it can be nested.
Finally, if the subset of files you want to delete can't be easily expressed with a regular expression, a trick I often use is to list the files to a temporary text file, then edit it:
$ ls > list
$ vi list # Use your favorite text editor
I can then edit the list file manually, leaving only the files I want to remove, and then:
$ rm -f $(<list)
or
$ rm -f `cat list`
(Again, this assumes none of the file names contain funny characters, particularly spaces.)
Or, when editing the list file, I can add rm -f to the beginning of each line and then:
$ . ./list
or
$ source ./list
Editing the file is also an opportunity to add quotes where necessary, for example changing rm -f foo bar to rm -f 'foo bar' .
Just use multiline selection in sublime to combine all of the files into a single line and add a space between each file name and then add rm at the beginning of the list. This is mostly useful when there isn't a pattern in the filenames you want to delete.
[$]> rm abc.log.2012-03-14 abc.log.2012-03-27 abc.log.2012-03-28 abc.log.2012-03-29 abc.log.2012-03-30 abc.log.2012-04-02 abc.log.2012-04-04 abc.log.2012-04-05 abc.log.2012-04-09 abc.log.2012-04-10
A wild card would work nicely for this, although to be safe it would be best to make the use of the wild card as minimal as possible, so something along the lines of this:
rm -rf abc.log.2012-*
Although from the looks of it, are those just single files? The recursive option should not be necessary if none of those items are directories, so best to not use that, just for safety.
I am not a linux guru, but I believe you want to pipe your list of output files to xargs rm -rf. I have used something like this in the past with good results. Test on a sample directory first!
EDIT - I might have misunderstood, based on the other answers that are appearing. If you can use wildcards, great. I assumed that your original list that you displayed was generated by a program to give you your "selection", so I thought piping to xargs would be the way to go.
if you want to delete all files that belong to a directory at once.
For example:
your Directory name is "log" and "log" directory include abc.log.2012-03-14, abc.log.2012-03-15,... etc files. You have to be above the log directory and:
rm -rf /log/*

Resources