I wrote a simple bash script (I’m pretty new to it, you know!) to accept a directory as its argument and print its listing, testing for files and directories. Here’s how I approached it:
#!/bin/bash # Lists all files and directories (non-recursively) in a specified directory if [ $# -gt 1 ]; then echo "Error. Please specify only one directory. ($#)" exit fi if [ -z $1 ]; then echo "No directory specified. Exiting." exit fi echo "Listing for $1:" $dirs=`ls $1` echo "Dirs: $dirs" # Just to confirm if all is well # Loop through and print for i in $dirs; do if [ -f $i ]; then echo "File: $i" elif [ -d $i ]; then echo "Directory: $i" fi done
The problem is in my for loop. When I run this script and feed it my home directory, I get this error:
./list_files_and_dirs.sh: line 16: =Calibre: command not found
I know I’m making a mistake in command substitution involving variables, but I just don’t know what. Someone please help!
================= Update =================
Here’s the new (final section) code as per inputs from answers:
dirs=`ls "$1"` #echo "Dirs: $dirs" # Just to confirm if all is well IFS=$'n' # Loop through and print for i in $dirs; do if [ -f "$i" ]; then echo "File: $i" elif [ -d "$i" ]; then echo "Directory: $i" fi done
Answer
Note: I’ve assumed you’re teaching yourself Bash. Do not use this code in production. find "$directory" -maxdepth 1 -type d
will get you the directories, -type f
will get you the files.
Since it is complaining about line 16, let’s have a look at it:
$dirs=`ls $1`
If you want to assign to a variable, you should not include the $
. I’m guessing you meant:
dirs=`ls $1`
What’s happening now, is this:
$dirs
is probably empty, so substituted with nothing.- The
ls
command is run, and its output substituted in the ‘command’. - The first file in your directory is called
Calibre
, leaving you with the command:=Calibre x y z ...
=Calibre
is not a valid command, thus the error.
However, we’re not there yet: this will go wrong if there are spaces in any of the filenames. To fix that, you need to do more:
- You need to include
IFS=$'n'
somewhere before thefor
loop. This sets the fields separator to the linefeed character, which stops thefor
loop from splitting up the files on the spaces or tabs (it’s technically possible for a file to have a linefeed in its filename as well: you’re unlikely to ever encounter such a file and it won’t cause serious problems in this case if you do run into such a file, but it’s worth being aware of the possibility in case it ever does matter). - In order for a filename with spaces not to turn into several different arguments to
-f
and-d
, you need to put quotes$i
. (So:[ -f "$i" ]
and[ -d "$i" ]
. In order to support directories with spaces in them, you should do the same for$1
where it is used.