ls(1) acts strangely when input is a variable / subcommand or just typed

2

D

I'm facing a issue on ls(1) that I'm almost sure that it's a silly thing that I'm just letting pass away. Anyways, I can't understand really why this isn't working.

I'm using bash for cygwin (Don't ask why... I just have to :( ) Here's the full (meaningful) --version output: GNU bash, version 4.4.12(3)-release (x86_64-unknown-cygwin)

I was messing around with cygpath to convert the unix / windows paths for me, so I can stay most of the time on the terminal and yet be able to get the windows paths and vice versa.

So far, so good... but an annoying thing on NT is that so much paths has spaces and other chars that don't quite fit on the paths, like ( ). To help me out with that I just wrote a oneliner script to escape all the paths with backslashes, so I'll have a valid path no matter what craziness windows put on them.

So far, still so good... But then I ran into a problem the ls(1) gets confused about the paths, it's kind hard to explain so will put some examples!

## Lets imagine that I want to get the "unix" version of C:\Program Files (x86)
## And for sake of simplicty I'll call the oneliner sript as unix_path.

unix_path "C:\Program Files (x86)"
##  prints /cygdrive/c/Program\ Files\ \(x86\)

my_path=$(unix_path "C:\Program Files (x86)");
echo $my_path;
##  prints /cygdrive/c/Program\ Files\ \(x86\)

## Until now, we're good!
## But the next commands really bugs me...

ls $my_path;
##  ls: cannot access '/cygdrive/c/Program\': No such file or directory
##  ls: cannot access 'Files\': No such file or directory
##  ls: cannot access '\(x86\)': No such file or directory

ls $(unix_path "C:\Program Files (x86)")
##  Same as before...
##  ls: cannot access '/cygdrive/c/Program\': No such file or directory
##  ls: cannot access 'Files\': No such file or directory
##  ls: cannot access '\(x86\)': No such file or directory

ls "$my_path";
##  ls: cannot access '/cygdrive/c/Program\ Files\ \(x86\)': No such file or directory

## Now is very crazy, let's imagine that I type /cygdrive/c/Program\ Files\ \(x86\)
## by hand or just paste it.
ls /cygdrive/c/Program\ Files\ \(x86\)
##   I'll not post but the listing are correct!

I really don't understand why ls(1) isn't correct when I call it with $() or with the $var_name_here but yet is correct when I type the path. Notice that the path is identical for both ways!

Any help here would be great! Thanks!

n2omatt

Posted 2017-07-23T16:37:10.637

Reputation: 21

Answers

2

Because

ls $my_path;

becomes

ls /cygdrive/c/Program Files (x86)

because the backslashes aren't really part of the path, they are just a trick in bash "literals".

So ls is given three distinct files names /cygdrive/c/Program, Files and (x86). To have ls see one single file name with spaces inside, use:

ls "$my_path"

In practice in bash you put double quotes around all the strings that can contain spaces and that you want to be seen as a single unit. $-subtitution still happens inside double quotes (but doesn't happen inside single quotes)

xenoid

Posted 2017-07-23T16:37:10.637

Reputation: 7 552

Hi @xenoid thanks for the reply ;D I understand your reasoning but it still not works, as you can see on my post, the second to last example is already enclosing the var in quotes Do you have any other idea, and again thanks ;D – n2omatt – 2017-07-25T01:21:48.993

2@n2omatt You have to have double-quotes around the variable reference and NOT have escapes in the variable value. Try my_path='/cygdrive/c/Program Files (x86)'; ls "$my_path". So that oneliner you wrote to add escapes? Don't use it, it's part of the problem. – Gordon Davisson – 2017-07-25T03:06:35.387