简体   繁体   中英

understanding shell script— IFS, '' , ##

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM