Linux Shell script what dirname and ? means? - linux

Can any body tell me what this command means?
selfDir=$(cd "$(dirname "$0")"; pwd) ?
I know
$0 = running script name
pwd = current working dir
cd = to change dir
What I need is what is dirname? and what ? means at end to make this line completely understandable.

The dirname command removes the trailing / component from the NAME and prints the remaining portion. If the NAME does not contain / component then it prints '.' (means current directory)
Dirname Command Example:
Remove the file name from absolute path.
Let say my directory path is /usr/local/bin/add.sh. Now i want to remove /add.sh and display only /usr/local/bin, then we can use the dirname command.
dirname /usr/local/bin/add.sh
/usr/local/bin
NAME
dirname - strip non-directory suffix from file name
SYNOPSIS
dirname NAME
dirname OPTION
DESCRIPTION
Print NAME with its trailing /component removed; if NAME contains no /’s, output ‘.’ (meaning the current directory).
Edit:
Also, Some characters have special functions in linux commands ? <-- Matches one character
Source

Related

How to print only folder names where same name of file exists

I am trying to write a script where all matching file names exist.
For example, I have a file TEST123 in many subfolders under /opt . I have a list of file names. So, I need to print only folder names which has the same file name .
Desired output :
TEST123
/opt/test2
/opt/test3
I am not sure how to use grep command :
I have a list "elements.txt" with full path of file names. And I cutted only the filenames at the end to " onlyfile.txt" .
This is how elements.txt look with many different file names, some of them has duplicated and some dont.
/opt/test2/TEST123
/opt/test3/TEST123
/opt/test2/TEST577
/opt/test6/SUNNY
/opt/test8/SUNNY
This is onlyfile.txt:
TEST123
TEST577
SUNNY
and many more files
And need to loop with the filename , like
for item in `cat onlyfile.txt`
do
grep elements.txt
done
It is giving me all outputs, but I need only folder names .
Any help would be appreciated.!
To get the directory of every file named TEST123, use the find command:
find /opt -name TEST123 -printf "%h\n"
The output will be:
/opt/test2
/opt/test3
The %h specifier will output the directory of the file. See the find manpage for more information.
In this case i think you need more than one loop.
for item in `cat onlyfile.txt`; do
for path in `cat elements.txt |grep $item`; do
dirname $path
done
done
First loop iterate filenames
Second loop searches filenames in paths and strip file name from them

How to add sequential numbers say 1,2,3 etc. to each file name and also for each line of the file content in a directory?

I want to add sequential number for each file and its contents in a directory. The sequential number should be prefixed with the filename and for each line of its contents should have the same number prefixed. In this manner, the sequential numbers should be generated for all the files(for names and its contents) in the sub-folders of the directory.
I have tried using maxdepth, rename, print function as a part. but it throws error saying that "-maxdepth" - not a valid option.
I have already a part of code(to print the names and contents of text files in a directory) and this logic should be appended with it.
#!bin/bash
cd home/TESTING
for file in home/TESTING;
do
find home/TESTING/ -type f -name *.txt -exec basename {} ';' -exec cat {} \;
done
P.s - print, rename, maxdepth are not working
If the name of the first file is File1.txt and its contents is mentioned as "Louis" then the output for the filename should be 1File1.txt and the content should be as "1Louis".The same should be replaced with 2 for second file. In this manner, it has to traverse through all the subfolders in the directory and print accordingly. I have already a part of code and this logic should be appended with it.
There should be fail safe if you execute cd in a script. You can execute command in wrong directory if you don't.
In your attempt, the output would be the same even without the for cycle, as for file in home/TESTING only pass home/TESTING as argument to for so it only run once. In case of
for file in home/TESTING/* this would happen else how.
I used find without --maxdepth, so it will look into all subdirectory as well for *.txt files. If you want only the current directory $(find /home/TESTING/* -type f -name "*.txt") could be replaced to $(ls *.txt) as long you do not have directory that end to .txt there will be no problem.
#!/bin/bash
# try cd to directory, do things upon success.
if cd /home/TESTING ;then
# set sequence number
let "x = 1"
# pass every file to for that find matching, sub directories will be also as there is no maxdeapth.
for file in $(find /home/TESTING/* -type f -name "*.txt") ; do
# print sequence number, and base file name, processed by variable substitution.
# basename can be used as well but this is bash built in.
echo "${x}${file##*/}"
# print file content, and put sequence number before each line with stream editor.
sed 's#^#'"${x}"'#g' ${file}
# increase sequence number with one.
let "x++"
done
# unset sequence number
unset 'x'
else
# print error on stderr
echo 'cd to /home/TESTING directory is failed' >&2
fi
Variable Substitution:
There is more i only picked this 4 for now as they similar.
${var#pattern} - Use value of var after removing text that match pattern from the left
${var##pattern} - Same as above but remove the longest matching piece instead the shortest
${var%pattern} - Use value of var after removing text that match pattern from the right
${var%%pattern} - Same as above but remove the longest matching piece instead the shortest
So ${file##*/} will take the variable of $file and drop every caracter * before the last ## slash /. The $file variable value not get modified by this, so it still contain the path and filename.
sed 's#^#'"${x}"'#g' ${file} sed is a stream editor, there is whole books about its usage, for this particular one. It usually placed into single quote, so 's#^#1#g' will add 1 the beginning of every line in a file.s is substitution, ^ is the beginning of the file, 1 is a text, g is global if you not put there the g only first mach will be affected.
# is separator it can be else as well, like / for example. I brake single quote to let variable be used and reopened the single quote.
If you like to replace a text, .txt to .php, you can use sed 's#\.txt#\.php#g' file , . have special meaning, it can replace any singe character, so it need to be escaped \, to use it as a text. else not only file.txt will be matched but file1txt as well.
It can be piped , you not need to specify file name in that case, else you have to provide at least one filename in our case it was the ${file} variable that contain the filename. As i mentioned variable substitution is not modify variable value so its still contain the filename with path.

How to get a folder name in linux bash from a directory

There will be directory which will have any number folder and may be files, I just need pick one random folder and need to process it ( move the folders , etc ..) I need process folder one by one. Need to ignore if there is any files.
I am tiring with below code able to get folder name but , seems there some hidden character or some thing which not giving proper output.
PROCESSING_FOLDER_NAME= ls -l /ecom/bin/catalogUpload/input/TNF-EU/ | grep '^d' | cut -d ' ' -f23 | head -1
#PROCESSING_FOLDER_NAME= echo $PROCESSING_FOLDER_NAME | tr -d '\n\r'
#PROCESSING_FOLDER_NAME=${PROCESSING_FOLDER_NAME%$'\n'}
#echo "PROCESSING_FOLDER_NAME is/$PROCESSING_FOLDER_NAME "
echo "/ecom/bin/catalogUpload/input/TNF-EU/$PROCESSING_FOLDER_NAME/"
output
Thanks_giving_Dec_08
/ecom/bin/catalogUpload/input/TNF-EU//
I am expecting the output should be /ecom/bin/catalogUpload/input/TNF-EU/Thanks_giving_Dec_08/
Here is my bash version.
GNU bash, version 4.2.50(1)-release (powerpc-ibm-aix6.1.2.0)
I mainly need the folder name (not full path) in variable, As the folder name which is processing need be use for emails to notify other, etc.
To get a random folder from a list of folders,
first put the list of folders in an array:
list=(/ecom/bin/catalogUpload/input/TNF-EU/*/)
Next, get a random index using the $RANDOM variable of the shell,
modulo the size of the list:
((index = RANDOM % ${#list[#]}))
Print the value at the selected index:
echo "${list[index]}"
To get just the name of the directory without the full path, you can use the basename command:
basename "${list[index]}"
As for what's wrong with the original script:
To store the result of a command in a variable, the syntax is name=$(cmd) instead of name= cmd
Do not parse the output of ls, it's not reliable
To get directories in a directory, you can use glob patterns like * ending with /, as in the above example */.

How to create directories automatically in linux?

I am having a file named temp.txt where inside this file it contains the following content
https://abcdef/12345-xyz
https://ghifdfg/5426525-abc
I need to create a directories automatically in linux by using only th number part from each line in the file.
So the output should be something like 12345 and 5426525 directories created.
Any approach on how to do this could be helpful.
This is the code that i searched and got from internet,wherein this code, new directories will be created by the file name that starts with BR and W0 .
for file in {BR,W0}*.*; do
dir=${file%%.*}
mkdir -p "$dir"
mv "$file" "$dir"
done
Assuming each URL is of the form
http[s]://any/symbols/some_digits-some_letters
Then you indeed could use the simple prefix and suffix modifiers in shell variable expansion.
${x##*/} expands to the suffix part of x that starts after the last slash /.
${y%%-*} expands to the prefix part of y before the first -.
while read x ; do
y=${x##*/}
z=${y%%-*}
mkdir $z
done < temp.txt

List absolute path for folder in Linux and Perl

I have a folder where inside that contains two folder such as below:
/vobs/code
/vobs/code/item
/vobs/code/image
I would like to obtain its absolute path of the two folder.In my perl script my code looks like this .
#folder = `cd /vobs/code/item;ls -d $PWD/**`; or
#folder = `cd /vobs/code/item;ls -d $PWD/*`;
From online it says that with the two wild card it will display files and directories while one wild card display folder but I tried in the console it gives files and folder also with or extra one wild card.
The result that I get after executing the perl script it does not give the folder path inside /vobs/code.Instead it display the root folder path.I put a pwd in between the cd and ls the pwd shows that it actually cd to the directory and perform the next command.
#folder = `cd /vobs/code/item;ls -d $pwd/*`
The command above produce the same output as the first and 2nd command as the pwd is lower case and it display root folder path.
I tried readlink -f but it requires the folder name else it will prompt error.I can try to get the file name and pwd the path and join it to become a variable but it is kind of hassle and I would take it as final resort if I could not find any solutions.Please help Thanks
You can use glob to expand a wildcard. Use grep to filter a list, -f and -d (see -x) check for files and directories, respectivelly.
my #files_and_directories = glob '/vobs/code/*';
my #files = grep -f, #files_and_directories;
my #directories = grep -d, #files_and_directories;
Have you considered abs_path?
use Cwd 'abs_path';
my $base_path = abs_path('vobs/code');
for my $dir ( qw/item image/ ){
my $path = abs_path(join("/",$base_path,$dir));
# Ofc, this will only work if vobs/code is in working directory.
my #files_in_dir = grep{ -f $_ }<$path/*>; # these will be absolute
}

Resources