0

Here is the code which I need to separate the files in array, but using the PIPE it is generating subshell so am not able to get access to arrays normal, executable and directory.and its not printing anything or don't know what is happening after #////////.Please help me regarding this.

i=0
j=0
k=0
normal[0]=
executable[0]=
directory[0]=
ls | while read line
do
if [ -f $line ];then
#echo "this is normal file>> $line"
normal[i]=$line
i=$((i+1))
fi

if [ -x $line ];then
#echo "this is executable file>> $line"
executable[j]=$line
j=$((j+1))
fi


if [ -d $line ];then
#echo "this is directory>> $line"
directory[k]=$line
k=$((k+1))
fi
 done

#//////////////////////////////////////
echo "normal files are"
for k in "${normal[@]}"
do
 echo "$k" 
done

echo "executable files are"

for k in "${executable[@]}"
do
echo "$k"
done


echo "directories are"
 for k in "${directory[@]}"
  do
  echo "$k"
  done
Ardeshana Milan
  • 373
  • 5
  • 23

2 Answers2

1

There are several flaws to your script :

  • Your if tests should be written with [[, not [, which is for binary comparison (more info : here). If you want to keep [ or are not using bash, you will have to quote your line variable, i.e. write all your tests like this : if [ -f "$line" ];then

  • Don't use ls to list the current directory as it misbehaves in some cases. A glob would be more suited in your case (more info: here)

  • If you want to avoid using a pipe, use a for loop instead. Replace ls | while read line with for line in $(ls) or, to take my previous point in acount, for line in *

After doing that, I tested your script and it worked perfectly fine. You should note that some folders will be listed under both under "executable files" and "directories", due to them having +x rights (I don't know if this is the behaviour you wanted).

As a side note, you don't need to declare variables in bash before using them. Your first 6 lines are thus un-necessary. Variables i,j,k are not necessary as well as you can dynamicaly increment an array with the following syntax : normal+=("$line").

Community
  • 1
  • 1
Aserre
  • 4,916
  • 5
  • 33
  • 56
  • According to the shell language specification, using `[[` produces unspecified results. See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_04 – William Pursell Jul 17 '14 at 13:04
  • If you are worried about whitespace in filenames (which is about the only reason to avoid piping `ls`) then you cannot use the unquoted `for line in $(ls)`. You must use `for line in "$(ls)"`. – William Pursell Jul 17 '14 at 13:05
  • @WilliamPursell I think you misunderstood what I meant. OP should replace `if [ -f $line ]` with `if [[ -f $line ]]`. This is what the link I provided added details about. Your link is about why you shouldn't use `[[` as it is reserved by the shell – Aserre Jul 17 '14 at 13:08
  • Read the link. Particularly the phrase "causing unspecified results" in reference to the use of `[[`. Using `[[` is fine if you are restricting yourself to bash, but this question isn't even tagged bash. – William Pursell Jul 17 '14 at 13:10
  • @WilliamPursell correct, though he shouldn't be using `ls` at all. `*` works just fine with files contianing space in name – Aserre Jul 17 '14 at 13:11
  • @WilliamPursell his scripts fails really badly when you run it using `#!/bin/sh` (even after replacing braces back to what they were). I take it as a sign it was developped with bash in mind :) – Aserre Jul 17 '14 at 13:13
  • 1
    @WilliamPursell The OP is already using arrays; it's safe to assume that `[[` is available as well, despite the lack of the `bash` tag. – chepner Jul 17 '14 at 13:33
  • @chepner There are more shells than bash that use arrays. Do all of them support `[[`? What is the advantage of using `[[` for a simple test of file type? `test` (aka `[`) works just fine for this. – William Pursell Jul 17 '14 at 14:21
  • I don't know, but do you honestly believe the OP is using a shell that isn't `bash`, supports arrays with the same syntax, but *doesn't* support `[[`? – chepner Jul 17 '14 at 15:57
  • @chepner. No, but I do believe that people using dash or other non-bash shells will often read questions like this and cherry-pick what they need (eg, they're not using arrays but are confused by the fact that the pipe spawns a subshell). Bashisms and their use are a significant issue that shell programmers should understand, and blindly advocating their use without at least mentioning the portability issue encourages bad practice. – William Pursell Jul 22 '14 at 15:06
0

The simplest thing to do is to keep the subshell open until you no longer need the arrays. In other words:

ls | { while read line; do 
...
echo "directories: ${directory[@]}" | tr ' ' \\n
}

In other words, add an open brace before the while and a closing brace at the end of the script.

William Pursell
  • 204,365
  • 48
  • 270
  • 300