How can i get the last word of a string linux - linux

For example:
im in this directory, for example, "home/linux/downloads/dir1" and I want to show the files in another directory.
I use: find /home/linux/files/
This command shows the files of the previous path like this:
/home/linux/files/file1.txt
/home/linux/files/file2.txt
using cut -d "/" -f4 i get file1.txt but if you change the path, this command no longer serves me.
There is a command that allows me to always get the last word of a string separated by /?

basename is what you want, because you're asking about paths. In Python it's os.path.basename().

You can use find's -exec for this:
find <directory> -exec basename {} \;
This will work in any directory. -exec tells find to execute the command for every file found. Here the command is basename, which returns only the file name without directory prefixes. Hope it helps.

Something like this:
path = '/home/linux/files/dir1'
lastdir = path.split('/')[-1]
yields 'dir1'

Related

Simple Bash Script that recursively searches in subdirs for a certain string

i recently started learning linux because a ctf contest is coming in the next months. The problem that I struggle with is that i am trying to make a bash script that starts from a directory, checks if the content is a directory or other kind of file. If it is a file,image etc apply strings $f | grep -i 'abcdef', if it is a directory cd to that directory and start over. i have c++ experience and i understand the logic but i can't really make it work.I can't succesfully implement the loop that goes thru all the subdirectories. All help would be appreciated!
you don not need a loop for this implementation. The find command can do what you are looking after.
for instance:
find /home -type f -exec sh -c " strings {} | grep abcd " \;
explain:
/home is you base directory can be anything
-type f: means a regular file
-exec from the man page:
"Execute command; true if 0 status is returned. All
following arguments to find are taken to be arguments to
the command until an argument consisting of ;' is encountered. The string {}' is replaced by the current
file name being processed everywhere it occurs in the
arguments to the command, not just in arguments where it
is alone, as in some versions of find. Both of these
constructions might need to be escaped (with a `') or
quoted to protect them from expansion by the shell. See
the EXAMPLES section for examples of the use of the -exec
option. The specified command is run once for each
matched file. The command is executed in the starting
directory. There are unavoidable security problems
surrounding use of the -exec action; you should use the
-execdir option instead."
If you want to just find the string in a file and you do not HAVE TO first find a directory and then a file and then search, you can just simply find the text with grep.
Go to the the parent directory and execute :
grep -iR "abcd"
Or from any place,
grep -iR "abcd" /var/log/mylogs/
Suggesting a grep command on find filter results:
grep "abcd" $(find . -type f)

How to get a list of the filenames of a specific folder in shell script?

I am trying to get all the filenames of a specific folder in a text file and I want only the names, not the relative path. I tried:
ls -1 a/b/c>filenames.txt
and its output is
file-2021-08-18.txt
file2-2021-08-18.js
file3-2021-08-18.json
file4-2021-08-19.json
which is what I want but only a specific day's file.
But when I do this:
ls -1 a/b/c/*2021-08-18*>filenames.txt
then the output is
a/b/c/file-2021-08-18.txt
a/b/c/file2-2021-08-18.js
a/b/c/file3-2021-08-18.json
I want only the filenames not the path of the files.
So, required output:
file-2021-08-18.txt
file2-2021-08-18.js
file3-2021-08-18.json
Is there any straightforward solution for this? OR I need to trim the output.
Thanks!!
When the argument to ls is a directory, it lists the filenames in the directory.
But when you use a wildcard, the shell expands the wildcard to all the filenames. So ls doesn't receive the directory as its argument, it receives all the filenames, and it lists them as given.
You can change to the directory and then list the matching files in the current directory:
(cd /a/b/c; ls *2021-08-18*) > filenames.txt
The parentheses make this run in a subshell, so the working directory of the original shell is unaffected.
With GNU find you may use the -printf option:
find a/b/c/ -type f -name "*2021-08-18*" -printf "%f\n" > filenames.txt
The directive %f picks out the file's name with any leading directories removed. Since -printf doesn't add a newline (\n) after the filename, we add one in order to match the required output.

Recursively find a directory and rename it in Shell Script

Im putting together a simple Shell script to run on a Linux Machine where I would:
1) Look for specific sub-directories within a main directory. These sub-dirs have a very specific naming convention (see below) and they are always 2 -max depth below the main directory.
2) Rename those sub-dirs to PART of its original name.
For example,
The sub directories are named:
andrew-11111
andrew-11112
andrew-11113
andrew-11114
The path to get to these sub dirs would look something like this:
myphotos/sailing/photos/andrew-1111
myphotos/sailing/photos/andrew-1112
myphotos/biking/photos/andrew-1113
myphotos/hiking/photos/andrew-1114
Id like take out the 'andrew-' from each of these sub dirs:
myphotos/sailing/photos/1111
myphotos/sailing/photos/1112
myphotos/biking/photos/1113
myphotos/hiking/photos/1114
Ive gotten as far as "finding" the sub dirs and listing them. I also understand how to copy and rename in command line. But putting it together at my level of shell scripting knowledge has been taking much more time than I can afford. Just a disclaimer, I am more than willing to learn, and have written a handful of shell scripts, but still new to this. Any help or examples are much appreciated!
Use wildcards to match the files in the nested directories
You can use bash parameter expansion operators to manipulate the filenames.
for file in myphotos/*/photos/*; do
name=${file##*/} # remove everything up to last /
dir=${file%/*} # remove everything from last /
newname=${name##*-} # remove everything up to last -
mv "$file" "$dir/$newname"
done
If you have the perl-based rename command, you can do:
rename 's#[^/]*-##' myphotos/*/photos/*
You can do it with this one-liner:
find -type d -name andrew\* -exec sh -c 'mv {} $(dirname {})/$(basename {} | cut -d"-" -f2)' \;
Explanation:
-type d find only directories
-name andrew\* self-explaining, you have to escape the * though
-exec sh -c '...' execute it in a subshell, so you can do the command substitution ($(...)) without problems
mv {} the {} holds whatever find finds
dirname gives you the path to a directory (try it out with a random path, my english is too bad now to explain better)
basename gives you the last directory of a given path
cut -d"-" -f2 use cut to cut off "andrew-". For this set the delimiter to - and select the field number 2

Linux terminal: Recursive search for string only in files w given file extension; display file name and absolute path

I'm new to Linux terminal; using Ubuntu Peppermint 5.
I want to recursively search all directories for a given text string (eg 'mystring'), in all files which have a given file extension (eg. '*.doc') in the file name; and then display a list of the file names and absolute file paths of all matches. I don't need to see any lines of content.
This must be a common problem. I'm hoping to find a solution which does the search quickly and efficiently, and is also simple to remember and type into the terminal.
I've tried using 'cat', 'grep', 'find', and 'locate' with various options, and piped together in different combinations, but I haven't found a way to do the above.
Something similar was discussed on:
How to show grep result with complete path or file name
and:
Recursively search for files of a given name, and find instances of a particular phrase AND display the path to that file
but I can't figure a way to adapt these to do the above, and would be grateful for any suggestions.
According to the grep manual, you can do this using the --include option (combined with the -l option if you want only the name — I usually use -n to show line numbers):
--include=glob
Search only files whose name matches glob, using wildcard matching as described under --exclude.
-l
--files-with-matches
Suppress normal output; instead print the name of each input file from which output would normally have been printed. The scanning of each file stops on the first match. (-l is specified by POSIX.)
A suitable glob would be "*.doc" (ensure that it is quoted, to allow the shell to pass it to grep).
GNU grep also has a recursive option -r (not in POSIX grep). Together with the globbing, you can search a directory-tree of ".doc" files like this:
grep -r -l --include="*.doc" "mystring" .
If you wanted to make this portable, then find is the place to start. But using grep's extension makes searches much faster, and is available on any Linux platform.
find . -name '*.doc' -exec grep -l 'mystring' {} \; -print
How it works:
find searches recursively from the given path .
for all files which name is '*.doc'
-exec grep execute grep on files found
suppress output from grep -l
and search inside the files for 'mystring'
The expression for grep ends with the {} \;
and -print print out all names where grep founds mystring.
EDIT:
To get only results from the current directory without recursion you can add:
-maxdepth 0 to find.

Unix: traverse a directory

I need to traverse a directory so starting in one directory and going deeper into difference sub directories. However I also need to be able to have access to each individual file to modify the file. Is there already a command to do this or will I have to write a script? Could someone provide some code to help me with this task? Thanks.
The find command is just the tool for that. Its -exec flag or -print0 in combination with xargs -0 allows fine-grained control over what to do with each file.
Example: Replace all foo's by bar's in all files in /tmp and subdirectories.
find /tmp -type f -exec sed -i -e 's/foo/bar/' '{}' ';'
for i in `find` ; do
if [ -d $i ] ; then do something with a directory ; fi
if [ -f $i ] ; then do something with a file etc. ; fi
done
This will return the whole tree (recursively) in the current directory in a list that the loop will go through.
This can be easily achieved by mixing find, xargs, sed (or other file modification command).
For example:
$ find /path/to/base/dir -type f -name '*.properties' | xargs sed -ie '/^#/d'
This will filter all files with file extension .properties.
The xargs command will feed the file path generated by find command into the sed command.
The sed command will delete all lines start with # in the files (feed by xargs).
Command combination in this way is very flexible.
For example, find command have different parameters so you can filter by user name, file size, file path (eg: under /test/ subfolder), file modification time.
Another dimension of flexibility is how and what to change in your file. For ex, sed command allows you to make changes on file in applying substitution (specify via regular expressions). Similarly, you can use gzip to compress the file. And so on ...
You would usually use the find command. On Linux, you have the GNU version, of course. It has many extra (and useful) options. Both will allow you to execute a command (eg a shell script) on the files as they are found.
The exact details of how to make changes to the file depend on the change you want to make to the file. That is probably best scripted, with find running the script:
POSIX or GNU:
find . -type f -exec your_script '{}' +
This will run your script once for a group of files with those names provided as arguments. If you want to do it one file at a time, replace the + with ';' (or \;).
I am assuming SearchMe is the example directory name you need to traverse completely.
I am also assuming, since it was not specified, the files you want to modify are all text file. Is this correct?
In such scenario I would suggest using the command:
find SearchMe -type f -exec vi {} \;
If you are not familiar with vi editor, just use another one (nano, emacs, kate, kwrite, gedit, etc.) and it should work as well.
Bash 4+
shopt -s globstar
for file in **
do
if [ -f "$file" ];then
# do some processing to your file here
# where the find command can't do conveniently
fi
done

Resources