2

There's a folder with a bunch of files and a perl scrip that lists them using ls with a wildcard like:

#!/usr/bin/perl
system("ls -U -1 dir/*");

I noticed that if I run exactly the same command from my bash terminal, I'll get the same results but they are in a different order.

Why might this be? Is the wildcard handled differently in both contexts?

Example:

mkdir dir
touch dir/a_0 dir/a1_0

terminal output:

dir/a_0
dir/a1_0

perl output:

dir/a1_0
dir/a_0
  • Can you post your output? – cuonglm Oct 10 '13 at 8:51
  • 3
    Do you see a difference between system("locale") in perl and locale in a terminal? perl's system() will typically call /bin/sh, what shell are you trying that in in the terminal? (note that it's shells that expand wildcards, so it depends on the shell implementation, and for some shells on the locale). – Stéphane Chazelas Oct 10 '13 at 8:52
  • 1
    Shell settings might also vary depending on whether it is started interactively or not. – peterph Oct 10 '13 at 9:29
  • @StephaneChazelas there's no difference in locale. – Luis Oct 10 '13 at 12:42
6

Perl's system("cmd") function typically forks a process, and in the child process, runs the system's shell (typically /bin/sh) with as arguments, ["sh", "-c", "cmd"], to have sh parse and execute that shell command line.

As an optimisation, it may sometimes do without a shell call, if cmd doesn't contain any shell meta-characters (like quoting characters or globbing characters or things like ;, &&...) other than space and tab, but here we have shell meta-characters since we have a *.

So, that ls -U -1 dir/* will be interpreted by the system's shell.

It is the shell that expands dir/* to a list of matching files passed to ls, so the way it's done depends on the shell.

In a terminal, you typically run your login shell, which is generally not /bin/sh. Also (as noted by peterph), that shell, since it's run interactively will typically read configuration files like ~/.zshrc (if the shell is zsh) where some settings might affect how globbing is done.

For instance:

My shell is zsh, and I've got a setopt dotglob in my ~/.zshrc, so:

$ echo *
.a d é f

Without reading the ~/.zshrc:

$ zsh -c 'echo *'
d é f
$ LC_ALL=C zsh -c 'echo *'
d f é

You'll notice that zsh honours the locale when sorting the list.

$ sh -c 'echo *'
d f é

sh (which in my case is Debian ash) doesn't honour the locale and sorts as if in the C locale.

If you want perl's system() to interpret the command line with a particular shell, you can write it:

system("zsh", "-c", "cmd");

When passed more that one argument, perl's system() never implicitly calls a shell, so above, it forks a process in which it runs /bin/zsh with ["zsh", "-c", "cmd"] as arguments.

  • I'm running Ubuntu, which makes sh default to dash (which is what perl will end up using) but uses bash for the terminal. Indeed, explicitly telling perl to use bash makes both options return the same results. Thanks @StephaneChazelas. – Luis Oct 10 '13 at 12:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.