Why does bash not distinguish case in file names? - bash

On macOS 10.12.5, bash 3.2.57 is generally case sensitive. This is not the case, however, with file names. For instance:
mbp:~ $ rmdir a
rmdir: a: No such file or directory
mbp:~ $ rmdir A
rmdir: A: No such file or directory
This was done to verify that neither a nor A exists.
mbp:~ $ mkdir a
mbp:~ $ mkdir A
mkdir: A: File exists
mbp:~ $ rmdir a A
rmdir: A: No such file or directory
What is the reason for such behavior?

The answer, as pointed out in the link given in the comments (thank you, Digital Chris), is that case insensitivity is not a feature of bash, but of the file system configuration (HFS+, not Case Sensitive).

Related

Cannot remove symbolic link to directory

I have a directory reference in my Downloads directory that contains a symbolic link (created with ln -s) to another directory. I get conflicting error message when trying to remove the symlink:
rm returns "Is a directory"
rmdir returns "Not a directory"
This only occurs with cellranger/ (followed by a forward slash) and not with cellranger.
[tom#rlgsw68 cellranger]$ pwd
/home/tom/Downloads/reference
[tom#rlgsw68 cellranger]$ ls -lth
lrwxrwxrwx 1 tom genome 33 Apr 4 14:52 cellranger -> /analysisdata/genomes/cellranger/
[tom#rlgsw68 cellranger]$ rm cellranger/
rm: cannot remove directory `cellranger/': Is a directory
[tom#rlgsw68 cellranger]$ rmdir cellranger/
rmdir: cellranger/: Not a directory
[tom#rlgsw68 cellranger]$ rm cellranger
Why does neither of these commands to remove the symlink work and why do these conflicting errors occur? What is the recommended way to remove symbolic links without removing the content in the source directory. rm -rf cellranger/ also does not remove the symlink (but does not return an error).
Information: I'm running a linux server (Debian 9.0). These errors occur with both bash and zsh. Ambiguous names have been removed from the example. I encountered this when a directory included a link to the parent directory in addition to the contents:
/home/tom/Downloads/reference/cellranger/cellranger/ -> /analysisdata/genomes/cellranger/
By putting a trailing slash you are referring to the directory the symlink points to, no longer the symlink itself. Printing the inode number (the number that a path refers to in the file system) shows the difference between dereferencing the symlink and the directory:
$ cd "$(mktemp --directory)"
$ mkdir a
$ stat --format %i a/
9
$ ln --symbolic a b
$ stat --format %i b
10
$ stat --format %i b/
9
This may be related to the fact that a symlink is never a directory, it is always just a file containing a path.

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.

cp cannot stat to ~/ in script

I am having a problem I just can't seem to get over in my bash script.
Whenever I try to copy using cp to home folder in a script I get
cp: cannot stat '~/file.txt': no such file or directory
My code is as follows:
#!/bin/bash
echo "file location"
read a
user inputs ~/file.txt
b=$(basename $a)
cp "$a" . /$b
Please help, it's probably a simple solution but I just can't figure it out.
Filename expansion isn't applied to variables, which can be checked with the following minimal example:
d="~"; ls $d
ls: cannot access ~: No such file or directory
Use the full path: /home/youruser/file.txt.
Alternatively, you can force the globbing with eval (but prefer not to.. it's eval..):
d=$(eval echo "$d")
echo $d # /home/user
You could do something like
expanded_path=$(echo "$d" | "s:^~:$HOME:")
(that is, subtstitute the initial ~ for $HOME manually)
or force the user to use the full path.
eval is evil (definitely for user-supplied input, it is).
If you just want to copy in the current dir while keeping the original name, you can do:
cp "$src" .
No need to play with basename.
You can just replace the ~ with $HOME:
read a
a=${a/\~/$HOME}
Now ~/file will become /home/user/file

How to copy all files except one file and one directory to another directory

I have the following directory
Dir A:
.git --> this is a directory
.gitignore
Dir B
Dir C
Dir E
file f
file g
Dir H
I want to copy everything except for (.git, .gitignore and Dir B) to Dir B. (Dir B is under Dir A)
I have tried the following
cp -r !(Dir B|.git|.gitignore) ~/Dir B
This works as expected when run it in terminal, but gives me an error when i run it from the Jenkins Shell window.
syntax error near unexpected token `('
Please Advice
Try this command -
rsync -r --exclude='.*' --exclude='DirB' ./ DirB
I am making the assumption that you do not want to copy any hidden file/directory to your destination folder i.e., Dir B. If it is so, just use the following commands and use them in the same shell as shown in the snapshot below:
shopt -s extglob
cp -r !(Dir B) 'Dir B'
shopt -u extglob
You don't have to explicitly specify the .git dir and .gitignore file. Also, you can change the destination dir mentioned above ('Dir B') as per your need/configuration.

Remove File on One Level of Directories only in KSH

I have a rm command which clears all the files in a particular directory.
#!/usr/bin/ksh
cd /asd/ded/ses/ddd/rty/leg/
rm *.sas7bdat
rm p_bt*
Unfortunately it clears all the files under this directory, but now I just want it to clear in "parent directory" i.e. "/asd/ded/ses/ddd/rty/leg/" and not in "/asd/ded/ses/ddd/rty/leg/21_11" which is the child directory inside it.
I know level rm is possible in bash. Does it change for KSH and if yes then how.
LonelySoul,
Chepner is correct. The default for 'rm' in ksh is to only remove the files in the current directory. You can remove files from the lower directories (recursively) by adding the '-r' option.
If you are observing different behavior, you may have an alias setup somewhere in your profile. Try entering 'whence rm' to see if there is an alias that is causing you unexpected behavior.
Examples.
>pwd
/tmp
>touch abc.txt
>mkdir ced
>touch ced/abc.txt
>rm abc.txt (will remove abc.txt in /tmp, but leave the file in directory ced.
>whence rm
rm -f

Resources