Prevent unix tree from displaying back-slash before spaces - unix

I use the command tree very often in command line (in Mac) and the tree structure of my current directory is listed as follows:
└── A\ File\ with\ Space.mp4
Is there an option to avoid displaying those back slashes?

My tree command has a -N option to print non printable chars as is.
tree -N
.
├── a dirname with spaces
└── myscript.sh
Otherwise, you could use printf and xargs:
tree | xargs -L 1 -I xxxx printf "%s\n" xxxx
.
├── a dirname with spaces
└── myscript.sh
Special chars in names are going to break it or display surprising result: \n ' " * etc.

Related

find directories

I have been trying to get to count all the empty folders in a certain directory. sub-directories excluded. i used the code below but i don't know how to define empty folders or folders that contain files.
echo "$(ls -l | egrep -l $1/* | wc -l)"
the $1 will be the user argument in the command line. example: ./script.sh ~/Desktop/backups/March2021.
Edit - im not allowed to use find command
Edit 2 - ls -l * | awk '/total 0/{print last}{last=$0}' | wc -l this script works but lists all folders even if the directory contains files and data or if the directory is empty.
What about this:
grep -v "." *
I mean the following: "." means any character (I'm not sure the syntax is correct), so basically you look for every file which not even contain any character.
You should not parse ls (directories or file names with newlines), so this solution is only for the assignment:
ls -d */ */* | cut -d/ -f1 | sort | uniq -u | wc -l
Explanation:
ls -d */ shows all directories. This is combined with ls -d */* which will also show contents in the directories.
The resulting output will show all directories.
Empty directories will be shown only once, so you want to look for unique lines.
With the cut you only see the name of the directory, not the files in the directory.
The sort could be skipped here, the ls will give sorted output. When you change the solution to find (next assignment?) the sort might be needed.
uniq can look for lines that occur once. The flag -u removes all lines that have duplicates, so it will show the unique lines in the output.

Unix tree ignore by pattern

man tree says
-I pattern
Do not list those files that match the wild-card pattern.
However, when I specify:
$ tree . -I .*~ -I *egg-info
I still see:
tree . -I .*~ -I *egg-info -I *.pyc
.
├── bin
├── LICENSE
├── Makefile
├── Makefile~
etc., it's still showing Makefile~ even though there's a terminal ~
What's the right syntax to get tree to ignore the pattern I have given it?
I see a few possibilities in your command. (Not knowing the 'flavor' of your unix, it's hard to pinpoint exactly).
.* Unix has "hidden" files. These are files whose name starts with a DOT. In Reg Ex, DOT ASTERISK means 0 or more characters. With file names, DOT ASTERISK means all hidden files and no visible files. Makefile~ is a visible file, not a hidden file, so it will not be excluded. You may need to replace DOT ASTERISK TILDE with ASTERISK TILDE.
-I = Exclude files, not exclude directories. If Makefile~ is a directory name, the -I may not exclude it.
File Globbing can bite you. -I M* will read the current directory and expand M* into every filename in the current directory. So, -I M* couild be "globbed" (or replaced) with -I Milk Money Margaret_is_a_Beauty. Use quotation marks around your wildcards. Try -I ".*~"or -I '.*~'
As per the man page extract you quoted, tree uses "wild-card pattern" which is a common synonym for "glob" or "glob pattern". In this paradigm * is the syntax for "a any number of any character".
(.* is the equivalent form in the regex paradigm.)
Your first ignore pattern -I .*~ is then searching for a . character followed by a * then a ~.
In this you simply mixed up the regex form with the glob form.
And as you can see, your other patterns worked the way you wanted because they don't have a prepended . in them.

trouble listing directories that contain files with specific file extensions

How to I list only directories that contain certain files. I am running on a Solaris box. Example, I want to list sub-directories of directory ABC that contain files that end with .out, .dat and .log .
Thanks
Something along these lines might work out for you:
find ABC/ \( -name "*.out" -o -name "*.log" \) -print | while read f
do
echo "${f%/*}"
done | sort -u
The sort -u bit could be just uniq instead, but either should work.
Should work on bash or ksh. Probably not so much on /bin/sh - you'd have to replace the variable expansion with something like echo "${f}" | sed -e 's;/[^/]*$;;' or something else that would strip off the last component of the path. dirname "${f}" would be good for that, but I don't recall if Solaris includes that utility...

Name a directory with specific pattern in Unix

How can i rename a directory by interchanging the digits and word in directory name.
e.g.
FRA-DEV_007583-K4C-rdf-1
FRA-DEV_007583-K4C-source-8
FRA-DEV_007584-K4C-rdf-19
FRA-DEV_007584-K4C-rdf-8
output should be
FRA-DEV_007583-K4C-1-rdf
FRA-DEV_007583-K4C-8-source
FRA-DEV_007584-K4C-9-rdf
FRA-DEV_007584-K4C-8-rdf
If you have all those files in the same directory, with no other files in there, you could use this script:
#! /bin/bash
nums=(`ls $1 | cut -d- -f5`)
words=(`ls $1 | cut -d- -f4`)
files=(`ls $1 | cut -d- -f1-3`)
complete_files=(`ls $1`)
len=${#complete_files[#]}
for (( i=0; i<${len}; i++ ));
do
newname=${files[$i]}-${nums[$i]}-${words[$i]}
mv $1${complete_files[$i]} $1$newname
done
Save this script as rename.sh in a directory OUTSIDE of the one where your files are. Then execute: bash rename.sh path/to/your/files/ don't forget the final slash, and make a backup first just in case.

How to copy files in shell that do not end with a certain file extension

For example copy all files that do not end with .txt
Bash will accept a not pattern.
cp !(*.txt)
You can use ls with grep -v option:
for i in `ls | grep -v ".txt"`
do
cp $i $dest_dir
done
Depending on how many assumptions you can afford to make about the characters in the file names, it might be as simple as:
cp $(ls | grep -v '\.txt$') /some/other/place
If that won't work for you, then maybe find ... -print0 | xargs -0 cp ... can be used instead (though that has issues - because the destination goes at the end of the argument list).
On MacOS X, xargs has an option -J that supports what is needed:
-J replstr
If this option is specified, xargs will use the data read from standard input to replace the first occurrence of replstr instead of append-
ing that data after all other arguments. This option will not affect how many arguments will be read from input (-n), or the size of the
command(s) xargs will generate (-s). The option just moves where those arguments will be placed in the command(s) that are executed. The
replstr must show up as a distinct argument to xargs. It will not be recognized if, for instance, it is in the middle of a quoted string.
Furthermore, only the first occurrence of the replstr will be replaced. For example, the following command will copy the list of files and
directories which start with an uppercase letter in the current directory to destdir:
/bin/ls -1d [A-Z]* | xargs -J % cp -rp % destdir
It appears the GNU xargs does not have -J but does have the related but slightly restrictive -I option (which is also present in MacOS X):
-I replace-str
Replace occurrences of replace-str in the initial-arguments with
names read from standard input. Also, unquoted blanks do not
terminate input items; instead the separator is the newline
character. Implies -x and -L 1.
You can rely on:
find . -not -name "*.txt"
By using:
find -x . -not -name "*.txt" -d 1 -exec cp '{}' toto/ \;`
Which copies all file that are not .txt of the current directory to a subdirectory toto/. the -d 1 is used to prevent recursion here.
Either do:
for f in $(ls | grep -v "\.txt$")
do
cp -- "$f" ⟨destination-directory⟩
done
or if you have a huge amount of files:
find -prune \! -name "*.txt" -exec cp -- "{}" ⟨destination-directory⟩ .. \;
Two things here to comment on. One is the use of the double hyphen in the invocation of cp, and the quoting of $f. The first guards against "wacky" filenames that begin with a hyphen and might be interpreted as options. The second guards agains filenames with spaces (or what's in IFS) in them.
In zsh:
setopt extendedglob
cp *^.txt /some/folder
(if you just want files)...
cp *.^txt(.) /some/folder
More information on zsh globbing here and here.
I would do it like this, where destination is the destination directory:
ls | grep -v "\.txt$" | xargs cp -t destination
Edit: added "-t" thanks to the comments

Resources