1

I am trying to create a bash alias to do the following:

  1. create a folder (with the current date as the folder name)
  2. move (or copy, either is fine with me) a file from the current folder into the new folder.

The filename is passed to the alias as a variable. E.g., my-alias file.txt

Here are a few of the ways I've tried to go about it (although I've tried quite a few more variations):

alias my-alias="mkdir -v -p '$(date +%F)-List' && cp $1 './$(date +%F)-List/$1' && cd '$(date +%F)-List'"

alias my-alias="mkdir -v -p '$(date +%F)-List' && cp $1 ./$(date +%F)-List/$1 && cd '$(date +%F)-List'"

alias my-alias="mkdir -v -p '$(date +%F)-List' && cd '$(date +%F)-List' && cp ../$1 ./$1"

I've tried many ways of writing the command, and none work.

What am I over looking?

This is on Mac OS which should be the same as most other Linux environments.

UPDATE: WHERE I WENT WRONG

I've realised where I was getting confused. I have a lot of aliases set up that "appear" to receive arguments. I set them up a long time ago (some years ago). I now realise that the aliases only seem to receive the arguments because an alias can process whatever follows it when entered on command line. But it will only process those "arguments" if they are at the end of the command string the alias refers to, and in the same order. So once I started trying to shuffle the arguments around in my aliases command string, the alias would break. So yes, the best approach is to use a function.

  • 1
    https://unix.stackexchange.com/questions/3773/how-to-pass-parameters-to-an-alias – steeldriver Jun 28 '20 at 02:34
  • @steeldriver Thanks. So are you suggesting I use a function instead of an alias? (as detailed in the accepted answer on that question). Or are you suggesting one of the other alias based answers on that question is applicable? – inspirednz Jun 28 '20 at 02:37

4 Answers4

4

If you must use alias, here's one that works by using -t to specify the destination directory before the actual argument for the file being moved:

alias my-alias="mkdir \$(date +%F); mv -t \$(date +%F)"

Works on Linux, I don't have a MacOS machine to test with though.

archfan
  • 51
  • 4
  • @HaukeLaging I did test the code (on Linux), I suppose I should have put that in the answer though. – archfan Jun 28 '20 at 03:23
  • If I run alias testalias='echo \$(date +%F)' I getbash: syntax error near unexpected token (' and that makes sense. My shell is GNU bash, Version 5.0.11. – Hauke Laging Jun 28 '20 at 03:38
  • @HaukeLaging The single quotes mean the $ isn't interpreted as escaping the $, but instead as wanting to execute echo \$(date +%F). I used double quotes in my answer, so the back slash escapes the $. alias testalias="echo $(date +%F)" and alias testalias='echo $(date +%F)' both will run without issues. – archfan Jun 28 '20 at 03:44
  • Right, I didn't read that carefully enough. Apologies. – Hauke Laging Jun 28 '20 at 03:55
  • I am marking Gordon Davidson's answer as the correct answer, because although your (@archfan) answer might work (I haven't actually tested it, but I assume it does), using a function is the better way to achieve what I needed to do. Thanks very much for your solution though. Much appreciated. – inspirednz Jun 29 '20 at 23:26
  • Unfortunately, mv -t is a GNU extension, and macOS's version of mv doesn't support it. – Gordon Davisson Jun 30 '20 at 00:06
3

Use a function instead of an alias. This is pretty much always the answer if you run into trouble getting an alias to work. Especially if you're trying to use arguments (e.g. $1), since aliases don't really take arguments.

Also, you should pretty much always put double-quotes around parameter and variable references (i.e. "$1" instead of just $1). And don't run date multiple times, since it's possible (if improbable) you'll get different results; run it once and store the result in a variable. Try this:

my-function() {
    local subdir="$(date +%F)-List"
    mkdir -v -p "$subdir" &&
        cp "$1" "$subdir/$1" &&
        cd "$subdir"
}
  • Even if there was no risk of getting different results one should never run unnecessary processes. Here it does not really matter but in other cases that can seriously degrade performance. – Hauke Laging Jun 28 '20 at 03:26
  • Marking this as the correct answer because although archfan's answer might work (haven't actually tested it, but I assume it does), using a function is the better way to achieve what I needed to do. – inspirednz Jun 29 '20 at 23:25
1

As the answers to the other questions indicate: Aliases are just not good at handling parameters. You can even see that:

param=foo; do something with "$param"

That is how parameters work: First (both in time and in the command line) you set them, then you use them. In contrast to that:

<alias string with several commands to be expanded> <parameter>

The parameter can be a parameter to the last command in the alias. That is not what you need.

You can do this with an alias by building it as a single command from the shell's perspective but it is questionable whether that is a useful approach:

alias testalias='bash -c "echo \$1; echo \$1-" bash'
$ testalias foo
foo
foo-

One argument against it is that the quoting is complicated. Even I got that wrong first.

Hauke Laging
  • 90,279
-1

You need to create a function. mkdir -v -p '$(date +%F)-List' will only get evaluated at the time the alias was created

rr0ss0rr
  • 342
  • You should provide the complete code so that it is clear what you mean. – Hauke Laging Jun 28 '20 at 03:56
  • Thanks for the suggestion. Your answer is too brief to make much sense to me or to be useful. I suggest you consider spelling it out a bit more than you have. Cheers... – inspirednz Jun 29 '20 at 23:28