Search code examples
bashls

Different behavior when running ls from within a script


I want to rename a couple of file named in an enumerated way. My previous approach was to use this command line:

FILES=`ls "someDir/"`; for f in $FILES; do echo "Processing file: $f"; done;

Echoing the filename is just for demo purposes. The above produces the expected output:

Processing file: File1
Processing file: File2
Processing file: File3
...

However when I run (what I thought is the same thing) the below script, it treats the whole ls output as one file and produces this output:

SCRIPT:
#!/bin/bash
FILES=`ls "someDir/"`

for f in $FILES
do
    echo "Processing file: $f"
done

OUTPUT:
Processing file: File1
File2
File3
...

I can't get my head around it. Also I'm not even sure wether it is ls which is producing this behavior. What is causing this behavior? And why?


Solution

  • See Why you shouldn't parse the output of ls(1), and rather use process-substitution to process command output.

    #!/bin/bash
    
    while IFS= read -r -d '' file; do
        echo "$file"
        # Do whatever you want to do with your file here
    done < <(find someDir/ -maxdepth 1 -mindepth 1 -type f -print0 | sort -z)
    

    The above simple find lists all files from the required directory (including ones with spaces/special-characters). Here, the output of find command is fed to stdin which is parsed by while-loop.

    To ordered sorting of files, add a sort -z piped to the find command output.