How to remove files with special characters - shell

How to remove a file(s) with strange name in ubuntu?
I used ssh-keygen, I think I copied the command line with the linebreak at the end and created two files with a very strange file name.
https://ibb.co/0mC5fMj
Try to delete
rm \'\'$\'r\'
But result:
rm: cannot remove ''\'''\''$'\''r'\''': No such file or directory

Try to add -- at the beginning of the file name.
$ rm -v -- #file
$ rm -v -- "#file"
Try to add ./ at the beginning of the file name.
$ rm -v ./#file
If the previous tips do not work, you can still remove it using the inode number with:
ls -li
output:
5133242 -rw-r--r-- 1 user #*%/file
then using find
$ find . -inum 5133242 -delete

Related

List all file, but not directories, recursively in BASh

I was wondering if there was a way to list all files from the current directory, but not the directories themselves, recursively in BASh.
EXAMPLE:
# list -r
/root/foo.txt
/root/log.txt
/root/tremp/passwd.list
But not:
# list -r
/root/
/root/foo.txt
/root/log.txt
/root/temp/
/root/tremp/passwd.list
Use find:
find . -type f
This will recursively search all files in the current directory. For instance:
$ mkdir temp
$ touch temp/passwd.list
$ touch log.txt
$ touch foo.txt
$ find . -type f
./foo.txt
./log.txt
./temp/passwd.list
You can also grep the provided output with this:
grep -v ./$
That is, list everything but the lines which finish with "/" (directory)

How to delete a file with a "Symbol for NULL" character (0x2400) in filename

ATTN: shell gods ;)
I can't seem to figure out how to delete a file with a unicode character 0x2400 in the filename on OSX (Example: ␀.test).
It's not a NULL character per-se, but a "symbol for null". (See: http://unicodelookup.com/#null/1)
Script - How to Reproduce
#!/usr/bin/env bash
dir="${HOME}/test_dir"
# Create Directory: ~/test_dir
if [ ! -d "${dir}" ]; then
printf "\nCreating Directory: ${dir}\n"
mkdir ${dir}
fi
# Create our character
char=$'\xE2\x90\x80'
# Create filename
file="${dir}/${char}.test"
# Create the File
printf "\nCreating File: ${file}\n"
touch ${file}
Delete the file... NOPE!
# Attempt 1 - Delete File
printf "\nDeleting File: ${file}\n"
rm -rf ${file}
Delete the whole directory... NOPE!
# Attempt 2 - Delete Directory
printf "\nDeleting Directory: ${file}\n"
rm -rf ${dir}
Delete the file via inode... NOPE!
# Attempt 3 - Delete File
inode=$(ls -i1 ${dir} | awk '{print $1}')
printf "\nDeleting via Inode: ${inode}\n"
find ${dir} -inum ${inode} -exec rm -i {} \;
The whole script should output something like this:
Creating File: /Users/bsmith/test_dir/␀.test
Deleting File: /Users/bsmith/test_dir/␀.test
rm: /Users/bsmith/test_dir/␀.test: Invalid argument
Deleting Directory: /Users/bsmith/test_dir/␀.test
rm: /Users/bsmith/test_dir/␀.test: Invalid argument
rm: /Users/bsmith/test_dir: Directory not empty
Deleting via Inode: 68592933
remove /Users/bsmith/test_dir/␀.test? y
rm: /Users/bsmith/test_dir/␀.test: Invalid argument
This command works for me:
rm ?.test
But sadly it is very probable that it will NOT work for you.
It is a known bug of osx:
Is it impossible to delete/move a file named “␀” on mac?
Rename folder with odd characters
The sure bet is to boot from a pen drive with some Linux OS, mount the file system in such Linux, and erase the file. It is sure that files with such names could be erased in Linux.

Truncate a directory in bash

Is there some elegant/simple way to delete the folder's contents in such a way there's no error output if it is empty?
The following command
$ rm -r $dir/*
doesn't work if the directory is empty, since in such a case, the wilcard * is not expanded and you get an error saying that rm cannot find file *.
Of course, the standard way is check if it is empty (with ls $dir | wc -w or find $dir -link 2 or any other related command), and deleting its contents otherwise.
Is there an alternative way not to check folder contents and only "truncate" the directory instead?
Bash
Simply,
$ rm -rf dir/*
(By default I believe) Bash doesn't complain about not finding anything with the glob. It just passes your literal glob through to your command:
$ echo dir/*
dir/*
When rm doesn't find a filename that has the literal glob character, it complains about not finding the file it's been asked to delete:
$ rm "dir/*"
rm: cannot remove ‘dir/*’: No such file or directory
$ echo $?
1
But if you force it, it won't complain:
$ rm -f "dir/*"
$ echo $?
0
I don't know if that refrain-from-complain is POSIX.
Do note, however, that if you don't have the shell option "dotglob" set, you'll miss files that start with a dot, AKA "hidden" files.
Generally
Zsh doesn't pass the literal glob through by default. You have to ask for it with "set -o nonomatch".
$ echo dir/*
zsh: no matches found: dir/*
$ echo $?
1
$ set -o nonomatch
$ echo dir/*
dir/*
For compatibility, I wouldn't use the above modern-Bash-specific "rm -rf dir/*", but would use the more general, widely-compatible solution:
$ find dir -mindepth 1 -delete
Find all files in "dir" at a minimum depth of 1 ("dir" itself is at depth 0), and delete them.
You can use rm -rf:
rm -rf "$dir"/*
As per man bash:
-f, --force
ignore nonexistent files and arguments, never prompt
rm -rf dir/*
does not delete hidden files which name starts with dot.
This is quite weird, when bash glob the *, it does not include .* files.
mkdir -p dir
touch dir/.a
rm -fr dir/*
ls dir/.a && echo I am not deleted
output is
dir/.a
I am not deleted
Besides, the rm -fr dir/* has another disadvantage: when there are too many files in the dir, the rm command will get too many arguments and results in error too many arguments. Also, it is very slow in that case.
Seems that the most reliable and fastest way is
find dir -mindepth 1 -delete

cp: silence "omitting directory" warning

I'm using the command cp ./* "backup_$timestamp" in a bash script to backup all files in directory into a backup folder in a subdirectory. This works fine, but the script keeps outputting warning messages:
cp: omitting directory `./backup_1364935268'
How do I tell cp to shut up without silencing any other warnings that I might want to know about?
The solution that works for me is the following:
find -maxdepth 1 -type f -exec cp {} backup_1364935268/ \;
It copies all (including these starting with a dot) files from the current directory, does not touch directories and does not complain about it.
Probably you want to use cp -r in that script. That would copy the source recursively including directories. Directories will get copied and the messages will disappear.
If you don't want to copy directories you can do the following:
redirect stderr to stdout using 2>&1
pipe the output to grep -v
script 2>&1 | grep -v 'omitting directory'
quote from grep man page:
-v, --invert-match
Invert the sense of matching, to select non-matching lines.
When copying a directory, make sure you use -R
cp -R source source_duplicate_copy_name
-R, -r, --recursive copy directories recursively
--reflink[=WHEN] control clone/CoW copies. See below
--remove-destination remove each existing destination file before
attempting to open it (contrast with --force)
--sparse=WHEN control creation of sparse files. See below
--strip-trailing-slashes remove any trailing slashes from each SOURCE

How can I delete all files in my folder, except Music -subfolder?

Duplicate
Unable to remove everything else in a folder except FileA
I guess that it is slightly similar to this:
delete [^Music]
However, it does not work.
Put the following command to your ~/.bashrc
shopt -s extglob
You can now delete everything else in the folder except the Music folder by
rm -r !(Music)
Please, be careful with the command.
It is powerful, but dangerous too.
I recommend to test it always with the command
echo rm -r !(Music)
The command
rm (ls | grep -v '^Music$')
should work. If some of your "files" are also subdirectories, then you want to recursively delete them, too:
rm -r (ls | grep -v '^Music$')
Warning: rm -r can be dangerous and you could accidentally delete a lot of files. If you would like to confirm what you will be deleting, try looking at the output of
ls | grep -v '^Music$'
Explanation:
The ls command lists directory contents; without an argument, it defaults to the current directory.
The pipe symbol | redirects output to another command; when the output of ls is redirected in this way, it prints filenames one-per-line, rather than in a column format as you would see if you type ls at an interactive terminal.
The grep command matches lines for patterns; the -v switch means to print lines that don't match the pattern.
The pattern ^Music$ means to match a line starting and ending with Music -- that is, only the string Music; the effect of the ^ (beginning of line) and $ (end of line) characters can also be achieved with the -x switch, as in grep -vx Music.
The syntax command (subcommand) is fish's way of taking the output of one command and passing it over as command-line arguments to another.
The rm command removes files. By default, it does not remove directories, but the -r ("recursive") option changes that.
You can learn about these commands and more by typing man command, where command is what you want to learn about.
So I was looking all over for a way to remove all files in a directory except for some directories, and files, I wanted to keep around. After much searching I devised a way to do it using find.
find -E . -regex './(dir1|dir2|dir3)' -and -type d -prune -o -print -exec rm -rf {} \;
Essentially it uses regex to select the directories to exclude from the results then removes the remaining files. Just wanted to put it out here in case someone else needed it.

Resources