Search code examples
kshls

Ksh ls -1 not working as expected


For the command ls, the option -1 is supposed to do run ls yielding an output with only one column (yielding one file per line). But if I put it in a script, it just shows every file jammed on one line, separated with spaces.

Script:

#!/bin/ksh

text=`ls -1`
echo $text

Folder contents:

test
  |--bob
  |--coolDir
  |--file
  |--notThisDirectoryAgain
  |--script.sh
  |--spaces are cool
  |--thatFile

Script Output:

bob coolDir file notThisDirectoryAgain script.sh spaces are cool thatFile

Output if I run ls -1 in the terminal (not in a script)

bob
coolDir
file
notThisDirectoryAgain
script.sh
spaces are cool
thatFile

Solution

  • it just shows every file jammed on one line, separated with spaces.

    You have to consider what it is.

    When you do

    text=`ls -1`
    

    that runs the program ls and presents the output as if you typed it in. So the shell gets presented with:

    ls=file1
    file2
    file3
    etc.
    

    The shell splits command-line tokens on whitespace, which by default includes a space, a tab, and a newline. So each filename is seen as a separate token by the shell.

    These tokens are then passed into echo as separate parameters. The echo command is unaware that the newlines were ever there.

    As I'm sure you know, all echo does is to write each parameter to stdout, with a space between each one.

    This is why the suggestion given by @user5228826 works. Change IFS if you don't want a newline to separate tokens.

    However, all you really had to do is to enclose the variable in quotes, so that it didn't get split:

    echo "$text"
    

    By the way, using `backticks` is deprecated and poor practice because it can be difficult to read, particularly when nested. If you run ksh -n on your script it will report this to you (assuming you are not using an ancient version). Use:

    text=$(ls -1)
    

    Having said all that, this is a terrible way to get a list of files. UNIX shells do globbing, this is an unnecessary use of the ls external program. Try:

    text=(*)             # Get all the files in current directory into an array
    oldIFS="$IFS"        # Save the current value of IFS
    IFS=$'\n'            # Set IFS to a newline
    echo "${text[*]}"    # Join the elements of the array by newlines, and display
    IFS="$oldIFS"        # Reset IFS to previous value