I am very new to shell scripting. Can anybody please explain me below lines in a very simple language or give me some link where I could find exactly the meanings I am searching for as written in code below:
How file is getting values? Is it getting from grep command written after done?
dir=$1 str=$2
while IFS= read -rd '' file; #What '' is doing?
do
base=${file##*/} #Please explain
dir=${file%/*} #Please explain
done < <(exec grep -ZFlR "$str" "$dir")
Thanks a ton in advance :)
The first line is used to read raw input passed by grep -ZFlR "$str" "$dir"
.
while IFS= read -rd '' file;
As you have specified -Z
in grep
it'll output a zero byte instead of a newline separated file names which usually grep does. So in read command is also specified with a -d
option referring the delimiter. As for IFS=
that is done to empty out IFS(Internal Field Separator) so as to preserve leading and trailing whitespace. More read here
The next line :
base=${file##*/}
deletes the longest match of any charater ended by a slash from the front of $file
.So something like :
/abc/def/jhg
-------->
strips off /abc/def/
Similarly the third line :
dir=${file%/*}
deletes the shortest match from the end of $file.
/abc/def/jhg
<----
strips off /jhg.
More read here .
As you didn't ask about the last line, I am assuming you're familiar that it is being redirected to the while loop.
while IFS= read -rd '' file; #What '' is doing?
do
Thie while loop will read each line returned by the command (exec grep -ZFlR "$str" "$dir")
. You see it is being used to 'feed' data to the loop at the end: done < <(exec grep -ZFlR "$str" "$dir")
Beginning with the while
loop you see IFS=
. That unsets
the Internal Field Separator
( IFS
) in bash which determines what separates a given string of words into separate fields. (the defaults IFS=$'space tab newline' which you see written like IFS=$' \\t\\n')
The while loop continues with read -rd '' file;
As discussed the input is coming from the exec grep..
expression at the end, and read -rd '' file
is reading that input up to the first ''
which is specified by -d
to be the delimeter to use with this read
. read
then stores the matching input in the variable file
. So the ''
is just serving as the delimeter for read
as specified by the -d
option to read
. (that explains why IFS
was unset at the beginning, they wanted to use the specific ''
delimiter in this case.
base=${file##*/} #Please explain
All this says is use parameter expansion
to delete eveything in string
beginning from the left up to ( and including ) the last /
character. (that is what ##
means). It is stipping the path information from the filename leaving only the filename in base
.
dir=${file%/*} #Please explain
Here this is similar parameter expansion, but here, we start from the right ( %
) and delete all characters up to, and including, the first /
character in file
leaving only the path
information in dir
. (makes sense)
done < <(exec grep -ZFlR "$str" "$dir")
Just feeds the loop as we discussed above.
$file gets its values from read
, which in turn reads from the input, which is redirected to at the end of the loop. <( ... )
is called "Process substitution", it basically behaves as a file whose contents is the output of the enclosed command. ##
and %
are instances of "Parameter expansion", they remove parts of the variable's value. You can search for all the terms and constructs in man bash
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.