How do I call a script with a wildcard pattern and two more arguments?

5,247

You call your script with

./script file_*.jpg jpg bak

But * gets expanded before it is passed to the script. Assuming you have the files file_1.jpg, file_2.jpg and file_3.jpg in your folder, this is what is invoked:

./script file_1.jpg file_2.jpg file_3.jpg jpg bak

which means that ${1} = file_1.jpg, ${2} = file_2.jpg and ${3} = file_3.jpg.

It might be better if you write your script such, that (in your example): ${1} = jpg and ${2} = bak. Then you can store those variables in your script, invoke shift 2 to get rid of them, and loop over all positional arguments simply by using

for file; do
    # do something
done
Share:
5,247

Related videos on Youtube

OMA
Author by

OMA

Updated on September 18, 2022

Comments

  • OMA
    OMA over 1 year

    I have this code to rename a bunch of files:

    #!/bin/bash
    for file in $1
        do
            mv -i "${file}" "${file/pattern/replacement}"
        done
    

    How do I replace "pattern" and "replacement" with $2 and $3?

    This code does not work:

    #!/bin/bash
    for file in $1
        do
            mv -i "${file}" "${file/$2/$3}"
        done
    

    I'm trying to rename using the following 3 arguments: file_*.jpg jpg bak (the result should be renaming all *.jpg files to *.bak files). But all it does is: mv -i file_01.jpg file_01.jpg (thus not renaming anything, since both mv arguments are identical, plus it stops at the first file, even when there are more *.jpg files). If I manually type jpg and bak into the bash script instead of $2 and $3 then it DOES work.

    • Ipor Sircer
      Ipor Sircer over 7 years
      It works for me.
    • pfnuesel
      pfnuesel over 7 years
      How do you invoke that script?
    • pfnuesel
      pfnuesel over 7 years
      Maybe add #!/usr/bin/env bash on top of the script, to make sure bash is invoked.
    • Арсений Черенков
      Арсений Черенков over 7 years
      It looks like you are rewriting rename command ...
    • OMA
      OMA over 7 years
      @Archemar: What rename command? Excuse my ignorance, but I don't know any rename command other than "mv"
    • Арсений Черенков
      Арсений Черенков over 7 years
      see man rename
    • OMA
      OMA over 7 years
      That command is not available for me. That's why I asked.
  • Stéphane Chazelas
    Stéphane Chazelas over 7 years
    As written, the script would work if called as ./script 'file_*.jpg' jpg bak as $1 is unquoted, so subject to split+glob, so that file_*.jpg would be expanded at that point. Your advice of having $1=pat, $2=ret and the rest the list of files is certainly best though (1- to avoid having to quote the pattern, 2- to avoid confusing users of other shells with different globs than bash, 3- to allow patterns like my file*...)
  • Stéphane Chazelas
    Stéphane Chazelas over 7 years
    consider using getopts to process your options. For instance, had you used getopts, you would have been able to do myscript -- -p -q files to replace -p with -q, and -ppp would have meant the same as -p.
  • Stéphane Chazelas
    Stéphane Chazelas over 7 years
    Your use of needle, haystack and wildcard words is confusing here.
  • Stéphane Chazelas
    Stéphane Chazelas over 7 years
    Note that if your boolean variables are made to contain only true or false, you can just do if "$found" instead of if [ "$found" = true ].
  • Stéphane Chazelas
    Stéphane Chazelas over 7 years
    Note that [ -f "$file" ] is not for file existence, but that the file exists and is a regular file (or symlink to regular file). That would exclude all other types of file like fifo, device, directory...
  • OMA
    OMA over 7 years
    Thanks a lot for reviewing my code and for all your comments, Stéphane! You're really helpful! I've implemented most of your suggestions, except getopts (I have to learn more about it) and if [ "$found" ], because that results in true when $found contains "false" (it's a string after all; I used strings since booleans don't exist in Bash). Also I don't mind the if [ -f "$file" ] checking only for regular files. It's all I need for now.
  • OMA
    OMA over 7 years
    BTW, it seems I'm reinventing the wheel here since there is an actual "rename" command I didn't know about the existence of, but it's not available on my machine, so my script will do. Plus, it's a nice exercise in Bash scripting :)
  • Stéphane Chazelas
    Stéphane Chazelas over 7 years
    yes, rename (both util-linux, perl's and now separate perl script with more extensions) and also mmv and zsh's zmv...
  • Stéphane Chazelas
    Stéphane Chazelas over 7 years
    Note that I said if "$found", not if [ "$found" ], as in run the command stored in $found (false and true being builtin bash commands), not the [ command with the content of $found as argument.
  • OMA
    OMA over 7 years
    Ah, I see. That's another intricacy I didn't know about :). About "mmv" and "zmv", those aren't available here, either
  • Stéphane Chazelas
    Stéphane Chazelas over 7 years
    zmv is a function shipped with zsh, so you can use all the expansion operators and glob operators of zsh (use autoload zmv from within zsh to enable it). You can search this site for zmv to see hundreds of examples.