gnu linux why does command "cd xyzdir && rm -rf abcfilename" fail? - linux

$ touch /tmp/abcd
$ ls -l /tmp/abcd
--w--w--w- 1 dinesh users 0 Oct 16 23:49 /tmp/abcd
$ x="cd /tmp && rm -rf abcd"
$ $x
$ pwd
/tmp
$ ls -l /tmp/abcd
--w--w--w- 1 dinesh users 0 Oct 16 23:49 /tmp/abcd
OTOH using x="cd /tmp; rm -rf abcd" works as I expected. So, what's wrong with my other approach because I want to be sure I am in that directory? $? always returns 0.
I guess always an oppty to learn. Thanks a lot. Dinesh
$ uname -a
Linux test-host 3.0.93-0.5-default #1 SMP Tue Aug 27 08:17:02 UTC 2013 (925d406) x86_64 x86_64 x86_64 GNU/Linux

We get the idea if we turn on trace output (0> is the prompt).
0>set -x
0>$x
+ cd /tmp '&&' rm -rf abcd
We see that && rm -rf abcd are just passed as extra arguments to the cd command. Obviously the parsing of && as a command list operator only takes place before parameter expansion, no more after $x has been substituted. Oddly, cd doesn't complain about the extra arguments - try:
cd . dumb and dumber
Logically
eval $x
works as desired.
OTOH using x="cd /tmp; rm -rf abcd" works as I expected.
You must be mistaken here.
0>$x
+ cd '/tmp;' rm -rf abcd
bash: cd: /tmp;: No such file or directory
Just as &&, ; is not parsed as a control operator here, but simply as the last character of the directory name /tmp; - consequently yielding an error.

Related

Delete dir with hyphen in name

I'm on CentOS 7.2 and I've somehow managed to create a folder called "-p". I can't seem to remove it now. I've tried the following:
rmdir -p
rmdir "-p"
rmdir \-p
rmdir "\p"
It's probably simple, but I'm struggling.
I guess worst case I'll move anything out of the parent folder and go for a rm -rf
Many thanks
EDIT: just figured out the command that did it (and has done it again)
mkdir –p /etc/redis /var/redis
...I don't even
You could do:
rm ./-p
And depending on the rm used:
rm -- -p
You can pass foldernames starting with hypens to mkdir and rmdir after a "double hypen".
Here's an example:
$ ls -1
$ mkdir -- -p
$ ls -1
-p
$ rmdir -- -p
$ ls -1
$

Does $PWD always equal $(realpath .)

Given
A modern Linux/UNIX/OSX (w/ realpath)
bash 4+ (even on OSX)
Is
"$PWD" == "$(realpath .)"
Always true?
It's pretty easy to test that this is not always the case.
$ mkdir /tmp/realdir
$ cd /tmp/realdir
$ echo $PWD
/tmp/realdir
$ ln -s realdir /tmp/fakedir
$ cd /tmp/fakedir
$ echo $PWD
/tmp/fakedir
$ realpath .
/tmp/realdir
so no, $PWD is not always the same as $(realpath .).
The bash manual indicates that the PWD variable is set by the built-in cd command. the default behaviour of cd is:
symbolic links are followed by default or with the -L option
This means that if you cd into a symlink the variable gets resolved relative to the symlink, not relative to the physical path. You can change this behavior for a cd command by using the -P option. This will cause it to report the physical directory in the PWD variable:
$ cd -P /tmp/fakedir
$ echo $PWD
/tmp/realdir
You can change the default behavior of bash using the -P option:
$ set -P
$ cd /tmp/fakedir
$ echo $PWD
/tmp/realdir
$ set +P
$ cd /tmp/fakedir
$ echo $PWD
/tmp/fakedir
This is of course notwithstanding the fact that you can assign anything you want to the PWD variable after performing a cd and it takes that value:
$ cd /tmp/fakedir
$ PWD=/i/love/cake
$ echo $PWD
/i/love/cake
but that's not really what you were asking.
It is not necessarily the case even when symbolic links are not used and PWD is not set by the user:
vinc17#xvii:~$ mkdir my_dir
vinc17#xvii:~$ cd my_dir
vinc17#xvii:~/my_dir$ rmdir ../my_dir
vinc17#xvii:~/my_dir$ echo $PWD
/home/vinc17/my_dir
vinc17#xvii:~/my_dir$ realpath .
.: No such file or directory
Note that under zsh, ${${:-.}:A} still gives the same answer as $PWD (the zshexpn(1) man page says about the A modifier: "Note that the transformation takes place even if the file or any intervening directories do not exist.").
Note that however, $PWD contains obsolete information. Using it may be a bad idea if some other process can remove the directory. Consider the following script:
rm -rf my_dir
mkdir my_dir
cd my_dir
echo 1 > file
cat $PWD/file
rm -r ../my_dir
mkdir ../my_dir
echo 2 > ../my_dir/file
cat ./file
cat $PWD/file
rm -r ../my_dir
It will output:
1
cat: ./file: No such file or directory
2
i.e. $PWD/file has changed.

List all files with file count as one of the output columns in $BASH?

Is there a way to show files similarly to ls -al that would also also show the file count of the directories listed? Sort of like an ls -al with ls -1 | wc -l as the final column? I've tried switching arguments out, and have pretty much given up on a pipe because I hit syntax errors whenever I try to manipulate the results much. Separately, they're golden, so I feel like I'm missing something obvious. A way to modify ls so it would also show file count of directories that it lists seems like it should be, at least. Does anyone know of a way to get this to work?
Directories
ls -al | awk '/^d/{d++}{print}END{print "Directories: "d}'
All files
ls -al | awk '{print}END{print "Files:" NR}'
I think something like this would be closer to what you want
> mkdir testdir && cd testdir && touch a && ln -s a b && mkdir c && touch c/{1..10}
> shopt -s dotglob; for i in *; do [[ -d $i ]] && paste <(ls -ld "$i") <(find "$i" -mindepth 1 | wc -l) || ls -l "$i"; done
-rw-rw-r-- 1 user user 0 Jul 8 00:04 a
lrwxrwxrwx 1 user user 1 Jul 8 00:04 b -> a
drwxrwxr-x 2 user user 4096 Jul 8 00:04 c/ 10

Chmod recursively

I have an archive, which is archived by someone else, and I want to automatically, after I download it, to change a branch of the file system within the extracted files to gain read access. (I can't change how archive is created).
I've looked into this thread: chmod: How to recursively add execute permissions only to files which already have execute permission as into some others, but no joy.
The directories originally come with multiple but all wrong flags, they may appear as:
drwx------
d---r-x---
drwxrwxr-x
dr--r-xr--
Those are just the few I've discovered so far, but could be more.
find errors when tries to look into a directory with no x permission, and so doesn't pass it to chmod. What I've been doing so far, is manually change permissions on the parent directory, then go into the child directories and do the same for them and so on. But this is a lot of hand labour. Isn't there some way to do this automatically?
I.e. how I am doing it now:
do:
$ chmod -R +x
$ chmod -R +r
until I get no errors, then
$ find -type f -exec chmod -x {} +
But there must be a better way.
You can use chmod with the X mode letter (the capital X) to set the executable flag only for directories.
In the example below the executable flag is cleared and then set for all directories recursively:
~$ mkdir foo
~$ mkdir foo/bar
~$ mkdir foo/baz
~$ touch foo/x
~$ touch foo/y
~$ chmod -R go-X foo
~$ ls -l foo
total 8
drwxrw-r-- 2 wq wq 4096 Nov 14 15:31 bar
drwxrw-r-- 2 wq wq 4096 Nov 14 15:31 baz
-rw-rw-r-- 1 wq wq 0 Nov 14 15:31 x
-rw-rw-r-- 1 wq wq 0 Nov 14 15:31 y
~$ chmod -R go+X foo
~$ ls -l foo
total 8
drwxrwxr-x 2 wq wq 4096 Nov 14 15:31 bar
drwxrwxr-x 2 wq wq 4096 Nov 14 15:31 baz
-rw-rw-r-- 1 wq wq 0 Nov 14 15:31 x
-rw-rw-r-- 1 wq wq 0 Nov 14 15:31 y
A bit of explaination:
chmod -x foo - clear the eXecutable flag for foo
chmod +x foo - set the eXecutable flag for foo
chmod go+x foo - same as above, but set the flag only for Group and Other users, don't touch the User (owner) permission
chmod go+X foo - same as above, but apply only to directories, don't touch files
chmod -R go+X foo - same as above, but do this Recursively for all subdirectories of foo
You need read access, in addition to execute access, to list a directory. If you only have execute access, then you can find out the names of entries in the directory, but no other information (not even types, so you don't know which of the entries are subdirectories). This works for me:
find . -type d -exec chmod +rx {} \;
Try to change all the persmissions at the same time:
chmod -R +xr
To make everything writable by the owner, read/execute by the group, and world executable:
chmod -R 0755
To make everything wide open:
chmod -R 0777
Adding executable permissions, recursively, to all files (not folders) within the current folder with sh extension:
find . -name '*.sh' -type f | xargs chmod +x
* Notice the pipe (|)
Give 0777 to all files and directories starting from the current path :
chmod -R 0777 ./

How can I remove a file "--remove-files"?

I tested:
rm \-\-remove-files
but I am unable to remove it. How can I do it?
rm ./--remove-files.
Note that -- isn't interpreted by the shell, and by extension, escaping it with \ will have no effect.
$ ls -lah -- --remove-files
-rw-r--r-- 1 xistence xistence 0B May 4 19:29 --remove-files
$ rm -- --remove-files
$ ls -lah -- --remove-files
ls: --remove-files: No such file or directory
So what you want is to use the -- as one of the arguments to rm, that means it stops processing getopt's, after that anything is taken literally:
rm -- --remove-files
rm -- --remove-files
The solution is:
rm -- --remove-files
Source: http://www.cyberciti.biz/faq/unix-linux-remove-strange-names-files/

Resources