I am trying to write a script that iterates over an unspecified number of input values and performs the same operation on each. Something like the file ~/bin/trash:

#!/usr/bin/env bash

for f in "$@"
    mv f ~/trashcan

which I intend to use like so

$touch 2.txt 3.txt 4.txt  # create demo files
$trash *.txt

As written, when running this on Git Bash (on Windows) I get the following error:

bash: syntax error near unexpected token `2.txt'

closed as unclear what you're asking by user181255, Sparhawk, dhag, Jan, roaima Mar 1 '18 at 22:53

Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

  • 1
    Can you post the original script or at least a correct example? shellcheck.net – Tomasz Feb 28 '18 at 21:39
  • The error message you have written is unlikely to have come from the script you have posted. On that basis there's no point trying to answer this question as written - at least until you edit it. – roaima Mar 1 '18 at 22:53
  • @tomasz, that is the original script, copied and pasted from the file I was using to test this. – Steven C. Howell Mar 2 '18 at 15:08
  • @roaima, bash: syntax error near unexpected token '2.txt' is the original error message. When I made @GillesQuenot's recommended change, replacing mv f ~/trashcan with mv "$f" ~/trashcan, the error was resolved and the script functioned as intended. I updated the question to clarify that I experienced this when using Git Bash from Git for Windows. – Steven C. Howell Mar 2 '18 at 15:12

Try :

#!/usr/bin/env bash

for f; do 
    mv "$f" ~/trashcan
  • the $ 'sigil is mandatory to call a declared variable ($f)
  • no need for f in "$@" here
  • 5
    Umm... actually no need for for here. mv "$@" "$HOME/trashcan". – Kusalananda Feb 28 '18 at 22:01
  • 2
    I presume OP give just a tiny example, and have more processing, but true – Gilles Quenot Feb 28 '18 at 22:04

In your code, you have forgotten the $ in front of f in the loop body. This should also be properly quoted as "$f" to support filenames with spaces etc. I'm not sure this is the cause of your error message though (and I see nothing in the code that would cause that error to appear). The error I would expect is No such file or directory when trying to move a nonexisting f.

For a small utility like this, you could just turn it into a shell function in your ~/.bashrc file:

trash () {
    local trashcan="$HOME/trashcan"
    mkdir -p "$trashcan"

    mv -f -v "$@" "$trashcan"

This function makes sure that the trash folder actually exists before moving things into it. It will also perform the move verbosely, displaying the names of the things that are moved.

There is no need to iterate here as "$@" will correctly expand to the names given to the function on the command line.

The only reason I can see for wanting to actually iterate over the names is if you want to make sure that the target of the mv does not exist before performing the move (so that things in the trash won't get overwritten by new items). With mv from GNU coreutils, you can do that automatically with something like

mv -f -v --backup=numbered "$@" "$trashcan"

With non-GNU mv you may want that loop (this is replacing the mv in the shell function above):

local trash_ext="$RANDOM"

for name; do
    while [ -e "$trashcan/${name##*/}.$trash_ext" ]; do

    mv -f -v "$name" "$trashcan/${name##*/}.$trash_ext"

This is just a quick-and-dirty way of creating a unique name by adding random number after the filename. The ${name##*/} thing will expand to the basename (the filename part of the pathname) of $name and could be replaced by $( basename "$name" ).

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