How to grep all files beside current dir, parent dir and one definded? - linux

I have a folder with the following files / folders:
.test
README.md
/dist
/src
I want to grep all files beside dist. So the result should look like:
.test
README.md
/src
When I do
ls -a | grep -v dist
it will remove dist. But . and .. are present. However I require the -a to get files with dot prefix.
When I try to add ls -a | grep -v -e dist -e . -e .. there is no output.
Why will -e . remove all files? How to do it?

Better to use find with -not option instead of error prone ls | grep:
find . -maxdepth 1 -mindepth 1 -not -name dist
btw just for resolving your attempt, correct ls | grep would be:
ls -a | grep -Ev '^(dist|\.\.?)$'

If you use bash, you can do :
shopt -s extglob
echo .[^.]* !(dist)

Related

Bash script creates symlink inside directory aswell

I have a bash script:
for file in `find -mindepth 1 -maxdepth 1`
do
old=`pwd`
new=".${file##*/}"
newfile="$old/${file##*/}"
cd
wd=`pwd`
link="$wd/$new"
ln -s -f $newfile $link
cd $old
done
This is meant to create a symlink in the user's home directory with '.' prepended to all the files and directories in the current working directory. This works fine, however, it also creates a symlink inside any sub directories to the same directory. E.G. foo will now have a link at ~/.foo and foo/foo.
Is there any way I can fix this?
EDIT: Thanks to Sameer Naik and dave_thompson_085 I have changed it up a bit, but the problem still persists even when a alternate directory is given as an argument. It isn't a problem with sub directories it is that two links are being made, one to ~/.foo123 and one to foo123/foo123 not a link is being made to ~/ for foo1 and foo1/foo2.
for file in `ls -l | grep -v total | awk '{print $NF;}'`
do
old=`pwd`
wd=`cd $1 && pwd`
new=".${file}"
newfile="$wd/${file}"
cd
wd=`pwd`
link="$wd/$new"
ln -s -f $newfile $link
cd $old
done
Since you don't want recurse into sub-directories, try using
for file in `ls -l | grep -v ^d | awk '{print $NF;}'`
or use -type f in find to exclude subdirectories

remove unused folder and copy needed

I'm trying to remove all Folder with
rm -R !(foo|bar|abc)
exclude the given folder names, that could be two or more.
That works fine!
In the next step I need to copy the needed missing folder from another direction in this folder.
I tried following, but it doesn't work, and it should also be flexible with folder counts.
rm -R !($neededfolders)
ownedfolders=$(ls ./dest/) #
find ../source/ -maxdepth 1 -type d | grep "$neededfolders" | grep -v "$ownedfolders" | xargs cp -Rt ./dest/
My problem with the code is that grep won't use multiple names, I also tried to declare the ownedfolder, set the second grep to
grep -v ${ownedfolder[i]}
and put the whole thing in a for loop, but these ends in a fallacy.
Many thanks!
You can use a for loop:
needed='#(foo|bar|abc)'
for dir in ../source/*/ ; do
dir=${dir%/}
if [[ $dir == ../source/$needed && ! -d dest/${dir##*/} ]] ; then
cp -R "$dir" dest/
fi
done
This avoids the ugly variable $ownedfolders populated by the output of ls.
You need to use the -E option to grep to enable extended regular expressions, which recognize | alternatives:
find ../source/ -maxdepth 1 -type d | grep -E "$neededfolders" | grep -v -E "$ownedfolders" | xargs cp -Rt ./dest/

delete file other than particular extension file format

i have a lot of different type of files in one folder. i need to delete the files but except the pdf file.
I tried to display the pdf file only. but i need to delete the other than pdf files
ls -1 | xargs file | grep 'PDF document,' | sed 's/:.*//'
You could do the following - I've used echo rm instead of rm for safety:
for i in *
do
[ x"$(file --mime-type -b "$i")" != xapplication/pdf ] && echo rm "$i"
done
The --mime-type -b options to file make the output of file easier to deal with in a script.
$ ls
aa.txt a.pdf bb.cpp b.pdf
$ ls | grep -v .pdf | xargs rm -rf
$ ls
a.pdf b.pdf
:) !
ls |xargs file|awk -F":" '!($2~/PDF document/){print $1}'|xargs rm -rf
Try inverting the grep match:
ls -1 | xargs file | grep -v 'PDF document,' | sed 's/:.*//'
It's rare in my experience to encounter PDF files which don't have a .pdf extension. You don't state why "file" is necessary in the example, but I'd write this as:
# find . -not -name '*.pdf' -delete
Note that this will recurse into subdirectories; use "-maxdepth 1" to limit to the current directory only.

Delete files with string found in file - Linux cli

I am trying to delete erroneous emails based on finding the email address in the file via Linux CLI.
I can get the files with
find . | xargs grep -l email#example.com
But I cannot figure out how to delete them from there as the following code doesn't work.
rm -f | xargs find . | xargs grep -l email#example.com
Solution for your command:
grep -l email#example.com * | xargs rm
Or
for file in $(grep -l email#example.com *); do
rm -i $file;
# ^ prompt for delete
done
For safety I normally pipe the output from find to something like awk and create a batch file with each line being "rm filename"
That way you can check it before actually running it and manually fix any odd edge cases that are difficult to do with a regex
find . | xargs grep -l email#example.com | awk '{print "rm "$1}' > doit.sh
vi doit.sh // check for murphy and his law
source doit.sh
You can use find's -exec and -delete, it will only delete the file if the grep command succeeds. Using grep -q so it wouldn't print anything, you can replace the -q with -l to see which files had the string in them.
find . -exec grep -q 'email#example.com' '{}' \; -delete
I liked Martin Beckett's solution but found that file names with spaces could trip it up (like who uses spaces in file names, pfft :D). Also I wanted to review what was matched so I move the matched files to a local folder instead of just deleting them with the 'rm' command:
# Make a folder in the current directory to put the matched files
$ mkdir -p './matched-files'
# Create a script to move files that match the grep
# NOTE: Remove "-name '*.txt'" to allow all file extensions to be searched.
# NOTE: Edit the grep argument 'something' to what you want to search for.
$ find . -name '*.txt' -print0 | xargs -0 grep -al 'something' | awk -F '\n' '{ print "mv \""$0"\" ./matched-files" }' > doit.sh
Or because its possible (in Linux, idk about other OS's) to have newlines in a file name you can use this longer, untested if works better (who puts newlines in filenames? pfft :D), version:
$ find . -name '*.txt' -print0 | xargs -0 grep -alZ 'something' | awk -F '\0' '{ for (x=1; x<NF; x++) print "mv \""$x"\" ./matched-files" }' > doit.sh
# Evaluate the file following the 'source' command as a list of commands executed in the current context:
$ source doit.sh
NOTE: I had issues where grep could not match inside files that had utf-16 encoding.
See here for a workaround. In case that website disappears what you do is use grep's -a flag which makes grep treat files as text and use a regex pattern that matches any first-byte in each extended character. For example to match Entité do this:
grep -a 'Entit.e'
and if that doesn't work then try this:
grep -a 'E.n.t.i.t.e'
Despite Martin's safe answer, if you've got certainty of what you want to delete, such as in writing a script, I've used this with greater success than any other one-liner suggested before around here:
$ find . | grep -l email#example.com | xargs -I {} rm -rf {}
But I rather find by name:
$ find . -iname *something* | xargs -I {} echo {}
rm -f `find . | xargs grep -li email#example.com`
does the job better. Use `...` to run the command to offer the file names containing email.#example.com (grep -l lists them, -i ignores case) to remove them with rm (-f forcibly / -i interactively).
find . | xargs grep -l email#example.com
how to remove:
rm -f 'find . | xargs grep -l email#example.com'
Quick and efficent. Replace find_files_having_this_text with the text you want to search.
grep -Ril 'find_files_having_this_text' . | xargs rm

Display only files and folders that are symbolic links in tcsh or bash

Basically I want do the following:
ls -l[+someflags]
(or by some other means) that will only display files that are symbolic links
so the output would look
-rw-r--r-- 1 username grp size date-time filename -> somedir
-rw-r--r-- 1 username grp size date-time filename2 -> somsdfsdf
etc.
For example,
to show only directories I have an alias:
alias lsd 'ls -l | grep ^d'
I wonder how to display only hidden files or only hidden directories?
I have the following solution, however it doesn't display the output in color :(
ls -ltra | grep '\->'
Find all the symbolic links in a directory:
ls -l `find /usr/bin -maxdepth 1 -type l -print`
For the listing of hidden files:
ls -ald .*
For only "hidden" folders - dot folders, try:
ls -l .**
Yes, the two asterisks are necessary, otherwise you'll also get . and .. in the results.
For symlinks, well, try the symlinks program:
symlinks -v .
(shows all symlinks under current directory)
ls -l | grep lrw
shows only symlinks (files and directories). Not sure how to get them colorful, though.
ls -lad .*
shows only hidden files/directories
ls -l | grep drw
shows directories only.
To display JUST the symlinks and what they link to:
find -P . -type l -exec echo -n "{} -> " \; -exec readlink {} \;
To limit to JUST THIS DIR
find -P . -maxdepth 1 -type l -exec echo -n "{} -> " \; -exec readlink {} \;
Example output (after ln -s /usr/bin moo):
./moo -> /usr/bin
You were almost there with your grep solution; let's focus on getting you COLOR again.
Try this:
ls --color=always -ltra | grep '->'
Improving a little on the accepted answer given by #ChristopheD (coudnt comment on the accepted answer since I dont have enough reputation)
I use an alias
findsymlinks <path> <depth>
where the alias is
alias findsymlinks "find \!:1 -maxdepth \!:2 -type l -print | xargs ls -l --color=auto"
Try file type flag and get rid of the appending #
ls -F /home/usr/foo | grep "#" | sed 's/#//'
For (t)csh:
ls --color=always -ltra | grep '\->'
(This is simply pbr's answer but with the hyphen escaped.)
Mac OSX
On OSX, ls works differently, so add this to your ~/.cshrc file:
setenv CLICOLOR_FORCE 1 # (equivalent of Linux --color=always)
And then call:
ls -G -ltra | grep '\->' # (-G is equivalent of ls --color)
For bash:
This provides a nice output.
sl=`find -L /path/to/target -xtype l`; for links in $sl; do ls --color=always -ltra $links; done | sed 's/^/ /'
Usage: foo $path
Uses current path if none specified.
#!/bin/bash
case "$1" in
-r)
find $2 -type l -print | while IFS= read line ; do ls -l --color=always "$line"; done
;;
--help)
echo 'Usage: foo [-r] [$PATH]'
echo
echo '-r Recursive'
;;
*)
ls --color=always -ltra $1 | grep '\->'
esac

Resources