Often developers forget about possible spaces in file and directory names, which can lead to any kind of trouble from corrupted awk parsing to terrible consequences like removing important stuff.
We'll consider the latter issue. E.g. when we find files we often need to perform some operations on them. So, this command
find . -name "*.log" | xargs rm -fwill remove all log files recursively...or maybe won't? The case is that 'find' produces output of one file (row) at a time and if the file path contains spaces it will be split by shell into several 'files' which 'rm' will try to delete. Consider the following project structure:
--> tree . ├── test ├── testdir │ └── remove.log └── test dir2 └── remove2.log 2 directories, 3 filesSo lets remove logs:
--> find . -name "*.log" | xargs rm -fand see what we have now:
--> tree . ├── testdir └── test dir2 └── remove2.log 2 directories, 1 fileOooops.... Where is the 'test' file? And why the 'remove2.log' is still here? Let's see what happens. I'll revert back to the original structure before the 'rm' and we'll run harmless 'ls' to see what xargs is getting:
--> find . -name "*.log" ./testdir/remove.log ./test dir2/remove2.log --> find . -name "*.log" | xargs ls -l ls: cannot access dir2/remove2.log: No such file or directory -rw-rw-r-- 1 aikikode aikikode 9 Oct 2 16:17 ./test -rw-rw-r-- 1 aikikode aikikode 13 Oct 2 16:18 ./testdir/remove.logSo shell is passing 3 files:
- ./testdir/remove.log
- ./test
- dir2/remove2.log
- set IFS variable before executing the command:
IFS="$(printf '\n\t')"
you should be aware that syntax and usage of IFS might differ from shell you are using - Use -exec option in find:
--> tree . ├── test ├── testdir │ └── remove.log └── test dir2 └── remove2.log 2 directories, 3 files --> find . -name "*.log" -exec rm -f {} \; --> tree . ├── test ├── testdir └── test dir2 2 directories, 1 file