Find the answer to your Linux question:
Page 1 of 2 1 2 LastLast
Results 1 to 10 of 16
To simplify things, I am illustrating the problem, just using the command line. Here is a list of the contents of a folder (all filenames): Code: root:~# ls AA BB ...
Enjoy an ad free experience by logging in. Not a member yet? Register.
  1. #1
    Just Joined!
    Join Date
    Sep 2013
    Posts
    5

    bash, ls, and [] - basis for a script to list contents


    To simplify things, I am illustrating the problem, just using the command line.

    Here is a list of the contents of a folder (all filenames):
    Code:
    root:~# ls
    AA  BB  bB  bbbb  cc  dd  EE  
    aa  Bb  bb  CC DD  ee  Cb
    Now, I just want to list anything beginning with lower case letters b, c, d.

    On Fedora 19.0
    Code:
    [root~]# ls [b-d]*
    bb  Bb  BB  bbbb  Cb  cc  CC  dd
    On Ubuntu 13.04
    Code:
    root:~# ls [b-d]*  
    bB  bb  bbbb  Cb  CC  cc  DD  dd
    What? Does not the [b-d]* mean, list anything beginning with letters b though d followed be any number of other characters?

    These are both bash shells, but as you can see the output is different. Would anyone like to explain what is going on?
    Last edited by mgdlinuxf; 09-26-2013 at 05:01 PM.

  2. #2
    Linux Enthusiast
    Join Date
    Jan 2005
    Location
    Saint Paul, MN
    Posts
    620
    The regular expression:
    Code:
     [b-d]
    is a set in this case the characters 'b', 'c', 'd'.

    The correct action is the file must start with lower cased 'b', 'c'. 'd'.

    Apparently "Fedora" is attempting to be "friendly" and is broken (The must be doing a caseless compare so that user does not have to worry about the case but this will bite them at some time in the future.)

    To get the results that Fedora returned the set should have been
    Code:
     [b-dB-D]*

  3. #3
    Linux Newbie
    Join Date
    Nov 2012
    Posts
    221
    hi,
    this is documented behaviour:
    Quote Originally Posted by man bash
    Note
    that when using range expressions like [a-z] (see below), letters of the other case may be
    included, depending on the setting of LC_COLLATE.
    you need to adapt LC_COLLATE:
    Code:
    $ ls -1
    aa
    AA
    bb
    bB
    Bb
    BB
    bbbb
    Cb
    cc
    CC
    dd
    DD
    ee
    EE
    $ oLC=COLLATE="$LC_COLLATE"
    LC_COLLATE=C
    $ printf '%s\n' ./[b-d]*)
    ./bB
    ./bb
    ./bbbb
    ./cc
    ./dd
    $ LC_COLLATE="$oLC_COLLATE"

  4. #4
    Just Joined!
    Join Date
    Sep 2013
    Posts
    5

    Solution provided

    Thank you, your code generates the same output on both the Ubuntu and Fedora systems. However, what I find interesting is that if I pipe the output to sort, the sort order is different. Fedora sorts with lower cap having precedence and Ubuntu sorts with upper case having precedence.

    Fedora
    Code:
    [root~]# ls [b-dB-D]*
    bb  bB  Bb  BB  bbbb  Cb  cc  CC  dd  DD
    
    [root~]# ls [b-dB-D]* | sort
    bb
    bB
    Bb
    BB
    bbbb
    Cb
    cc
    CC
    dd
    DD
    Ubuntu
    Code:
    root~# ls [b-dB-D]*
    BB  Bb  bB  bb  bbbb  Cb  CC  cc  DD  dd
    
    root~# ls [b-dB-D]* | sort
    BB
    Bb
    bB
    bb
    bbbb
    Cb
    CC
    cc
    DD
    dd
    Maybe the reason for this is touched on by the next post...
    Last edited by mgdlinuxf; 09-26-2013 at 05:02 PM.

  5. #5
    Just Joined!
    Join Date
    Sep 2013
    Posts
    25
    On SUSE I tried the same:

    Code:
    matsATlinux-7bll:~/tes> ls [b-d]*
    bb  bB  Bb  BB  bbbb  Cb  cc  CC  dd
    That is ridiculous!

    $LC_COLLATE is not set!

    If this is documented behavior, where is this documentation to be found? Google gave nothing useful for "bash lc_collate"

    Can it be that "ls" does not really support the construction [?-?] and that this is an erroneous behavior (instead of giving a failure code)?

    Code:
    matsATlinux-7bll:~/tes> ls b*
    bb  bB  bbbb
    matsATlinux-7bll:~/tes> ls B*
    Bb  BB
    matsATlinux-7bll:~/tes>
    Full distinction between upper and lower case as expected!
    Last edited by skitgubbe; 09-26-2013 at 04:55 PM.

  6. #6
    Just Joined!
    Join Date
    Sep 2013
    Posts
    5
    Yes, Watael, temporarily modifying LC_COLLATE to collate in strict numeric order fixes the issue. The output is exactly as one would expect.

    Code:
    root~# ls [b-d]*
    bB  bb  bbbb  cc  dd
    I have lots of reading to do on this issue and as you say it is "documented behavior". I somehow missed the topic in my initial Google search. So, I now can set LC_COLLATE=C in my script so that the change is not system wide.

    Thank you,
    Last edited by mgdlinuxf; 09-26-2013 at 05:03 PM.

  7. #7
    Linux Newbie
    Join Date
    Nov 2012
    Posts
    221
    Quote Originally Posted by skitgubbe
    If this is documented behavior, where is this documentation to be found?
    can't you read, you silly troll
    Quote Originally Posted by watael
    Quote Originally Posted by man bash
    ...
    if LC_whatever is not set then the default is $LANG, or $LC_ALL.

  8. #8
    Just Joined!
    Join Date
    Sep 2013
    Posts
    25
    Quote Originally Posted by mgdlinuxf View Post
    Code:
    [root~]# ls [b-d]*
    There is certainly no need to use this construct if there is difficulties of any kind. Simple and straightforward:

    Code:
    ls a* > tmp_file
    ls b* >> tmp_file
    ls c* >> tmp_file
    ls d* >> tmp_file
    cat tmp_file
    No collating problems what so ever!

  9. #9
    Just Joined!
    Join Date
    Sep 2013
    Posts
    5
    This is not very elegant coding, but using skitgubbe's suggestion...

    Code:
    [root@casper test]# ls
    aa  bb  bB  Bb  BB  bbbb  Cb  cc  CC  dd  DD  lst.sh
    [root@casper test]# ./lst.sh
    [root@casper test]# cat tmp_file
    bb
    bB
    bbbb
    cc
    dd
    [root@casper test]# cat lst.sh
    #!/bin/bash
    touch tmp_file
    t=tmp_file
    for x in {b..d}
    do
                    ls ${x}*>>$t
    done
    Last edited by mgdlinuxf; 09-26-2013 at 08:46 PM.

  10. #10
    Linux Newbie
    Join Date
    Nov 2012
    Posts
    221
    no need of a loop.
    and ls is useless.
    Code:
    $ printf '%s\n' ./{b..d}*
    ./bb
    ./bB
    ./bbbb
    ./cc
    ./dd
    or
    Code:
    $ printf '%s\n' ./{b,c,d}*
    ./bb
    ./bB
    ./bbbb
    ./cc
    ./dd

Page 1 of 2 1 2 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •