How do you check if a file ends in a certain file extension in bash? - eviltoast

Seriously. There doesn’t seem to be a way to do this. Every thing I ever try I just get bad substitution errors. The internet is full of people posting code that’s supposed to compare file extensions but none of it works. I’ve spent all morning trying everything I could find. I already gave up and I’m making this progeam in python instead but now I’m curious. How tf do you actually compare file extensions? If I have a folder fill of files and I want to run a command only on the png files, there seems to be no way to actually do this.

If someone posts “[[ $file == *.txt ]]” I’m going to fucking scream because THAT DOES NOT WORK. IT’S NOT VAILD BASH CODE.

  • Korthrun@lemmy.sdf.org
    link
    fedilink
    English
    arrow-up
    6
    ·
    5 months ago

    File extensions are just a text based convention. Renaming a file to end in .PDF does not make the file a valid PDF.

    You’re really saying there’s no way for a posix shell to take the text to the right of the last “.” character and then do simple string comparison on the result?

    Also why can’t you just use normal globbing to feed arguments to your command? Why do you need to involve flow control?

  • athairmor@lemmy.world
    link
    fedilink
    English
    arrow-up
    7
    arrow-down
    1
    ·
    edit-2
    5 months ago

    That works in bash 3.2 for me. So does this:

    [[ $file = *.txt ]]
    

    Maybe, the error is somewhere else in your code.

    • OpenStars@discuss.online
      link
      fedilink
      English
      arrow-up
      7
      arrow-down
      1
      ·
      5 months ago

      I loved this comment:

      What is the extension of the file xyzzy.tar.gz? Or plugh.cfg.saved? In other words, are you treating extension as a simple technical issue or a semantic one?

      For an OS that does not have file “extensions”, it’s entirely up to the user to define whatever it is that they are trying to accomplish.

  • yildolw@lemmy.world
    link
    fedilink
    English
    arrow-up
    3
    ·
    5 months ago

    Are you actually using Bash? You might be in a different shell. You can check with echo $SHELL

  • Nomecks@lemmy.ca
    link
    fedilink
    English
    arrow-up
    3
    ·
    edit-2
    5 months ago

    for i in ``ls *.png``; do something $i; done;

    (not formatting correctly)

    Is this sort of what you mean? You can tune the loop, but essentially you build a list of the files you want to do something against, then loop through it.

    • Korthrun@lemmy.sdf.org
      link
      fedilink
      English
      arrow-up
      5
      ·
      edit-2
      5 months ago

      What’s the benefit of spawning a subshell and executing “ls” here instead of just passing a glob to your loop?

      $ for lol in /usr/share/*.lm;do printf "I found a file named '%s'\n" "$lol";done
      
      I found a file named '/usr/share/out-go.lm'
      I found a file named '/usr/share/ragel.lm'
      I found a file named '/usr/share/ril.lm'
      I found a file named '/usr/share/rlhc-c.lm'
      I found a file named '/usr/share/rlhc-crack.lm'
      I found a file named '/usr/share/rlhc-csharp.lm'
      I found a file named '/usr/share/rlhc-d.lm'
      I found a file named '/usr/share/rlhc-go.lm'
      I found a file named '/usr/share/rlhc-java.lm'
      I found a file named '/usr/share/rlhc-js.lm'
      I found a file named '/usr/share/rlhc-julia.lm'
      I found a file named '/usr/share/rlhc-main.lm'
      I found a file named '/usr/share/rlhc-ocaml.lm'
      I found a file named '/usr/share/rlhc-ruby.lm'
      I found a file named '/usr/share/rlhc-rust.lm'
      
  • over_clox@lemmy.world
    link
    fedilink
    English
    arrow-up
    3
    arrow-down
    1
    ·
    5 months ago

    Let’s not forget that Linux filenames are case sensitive, so “.txt” ≠ “.TXT” ≠ “.Txt”

  • FigMcLargeHuge@sh.itjust.works
    link
    fedilink
    English
    arrow-up
    3
    arrow-down
    1
    ·
    edit-2
    5 months ago

    Maybe a little more context of what you want to run would help here. Find would work.

    find . -name “*.png” -exec whateveryouwanttodohere {} \;

    Or you could find, and then pass the arguments to xargs:

    find . -name “*.png” -print | xargs whateveryouwanttodohere

      • manicdave@feddit.uk
        link
        fedilink
        English
        arrow-up
        3
        arrow-down
        1
        ·
        5 months ago

        ls returns a list of files, the pipe passes that list to grep. The grep only returns results that match the string txt$. The $ symbol represents an end of line.

        • Korthrun@lemmy.sdf.org
          link
          fedilink
          English
          arrow-up
          5
          ·
          edit-2
          5 months ago

          That’s my bad, I asked an incomplete question.

          What does the approach of spawning a grep process and having ls send ALL of it’s output to grep have over just passing a glob to ls?

          Like:

          $ ls /usr/share/*.lm
          
          /usr/share/out-go.lm  /usr/share/ril.lm     /usr/share/rlhc-crack.lm   /usr/share/rlhc-d.lm   /usr/share/rlhc-java.lm  /usr/share/rlhc-julia.lm  /usr/share/rlhc-ocaml.lm  /usr/share/rlhc-rust.lm
          /usr/share/ragel.lm   /usr/share/rlhc-c.lm  /usr/share/rlhc-csharp.lm  /usr/share/rlhc-go.lm  /usr/share/rlhc-js.lm    /usr/share/rlhc-main.lm   /usr/share/rlhc-ruby.lm
          
          • manicdave@feddit.uk
            link
            fedilink
            English
            arrow-up
            2
            ·
            edit-2
            5 months ago

            Tbh, I didn’t even realise you could do that. I’m just used to using grep and worked backwards. Thanks for pointing it out.

  • GenderNeutralBro@lemmy.sdf.org
    link
    fedilink
    English
    arrow-up
    2
    arrow-down
    1
    ·
    edit-2
    5 months ago

    If someone posts “[[ $file == *.txt ]]” I’m going to fucking scream because THAT DOES NOT WORK. IT’S NOT VAILD BASH CODE.

    This is valid bash code.

    Do you understand how string substitution works? In this example, “file” is the name of a variable, and $file substitutes its value. If you have not set the value of file, then it won’t work.

    Edit: you should, as a rule of thumb, quote your variables. So "$file" instead of just $file. Quoting prevents some weird behavior with whitespace and special characters in the value. But either way, this is valid code and will work in the general case.

  • OneCardboardBox@lemmy.sdf.org
    link
    fedilink
    English
    arrow-up
    2
    arrow-down
    1
    ·
    5 months ago

    How about instead of starting with a list of all files in the directory, you use find to filter just the ones ending in .txt (or .TXT, it’s case insensitive)

    find $dir -maxdepth 1 -type f -iname "*.txt"