0

I am trying to run the following command inside a bash script:

rm -rf `ls -t ${FOLDER}/other_folder | awk 'NR>5'`

And I'm trying something like:

RM_CMD="$(rm -rf 'ls -t ${FOLDER}/other_folder | awk NR>5')"

Which later is used in a function, where I want the command to actually run.

I tried several variations, but it always fails, what is the correct approach here?

-edit-

Further Information

If I try something like

RM_CMD="rm -rf `ls -t ${FOLDER}/other_folder | awk 'NR>5'`"

It seems to try to execute the command immediately, which is not what I intend (I want to store the correct command for later execution), but it gets all the correct values, i.e., nothing empty.

-edit 2-

I tried splitting the commands as much as possible, like this:

LS_CMD="ls -t ${FOLDER}/other_folder"    
AWK_CMD="awk 'NR>5' ${LS_CMD}"    
RM_CMD="rm -rf '${AWK_CMD}'"

But it gives this problem:

+ ssh -t user@server 'rm -rf '\''awk '\''NR>5'\'' ls -t /full/path/to/folder/other_folder'\'''
bash: 5 ls -t /full/path/to/folder/other_folder: No such file or directory

migrated from serverfault.com Oct 5 '16 at 19:04

This question came from our site for system and network administrators.

  • Is there really a space after RM_CMD=? That doesn't belong there. – mzhaase Sep 30 '16 at 11:05
  • Thanks for pointing that out, I try to be careful with the extra spaces, and I think I haven't put any in the script. – Thin_icE Sep 30 '16 at 11:07
  • I'm voting to move this question to Unix & Linux since it's more about how unix works than about systems administration. In other words, the close vote currently on your question is not about actually closing but about moving. – Jenny D Sep 30 '16 at 13:49
  • You're absolutely correct, I'm sorry about that. – Thin_icE Sep 30 '16 at 15:01
3

Normally for questions like this, the answer is to read BashFAQ #50: "I'm trying to put a command in a variable, but the complex cases always fail!". Short summary: variables are for data, not executable code, and trying to put code in them has all sorts of problems.

But in this case there's another critical factor: you're going to run the command via ssh, which means that it'll be passed to the remote system as data, and parsed as a command by a shell on the remote computer. This means that it is reasonable to store the command (as data) in a variable in the script (on the local computer).

It looks to me like the biggest problem you're having is that when you use backquotes or $( ) (and they aren't in single-quotes), the command inside is executed immediately (on the local computer), and its output gets stored in the variable. To avoid this, you can escape the relevant characters when defining the variable:

RM_CMD="rm -rf \$(ls -t '${FOLDER}/other_folder' | awk 'NR>5')"

Note that I used $( ) instead of backquotes, since it's generally preferred. It looks to me like you've confused back-quotes with single-quotes at some points; they look similar, but have completely different effects. $( ) does essentially the same thing, but isn't visually ambiguous.

Also, I assume ${FOLDER} is a variable on the local computer, so that needs to be expanded immediately (and I added single-quotes around it in case it contains any spaces or other shell metacharacters); if it's to be expanded by the remote shell, use \"\${FOLDER|/other_folder\" instead. Actually, putting single-quotes around ${FOLDER} won't work if it contains any single-quotes itself. There's a way to fix this, but I haven't bothered here.

You could also use single-quotes in the variable assignment, but then you'd run into trouble with the single-quotes in the awk command (there's no clean way to nest single-quotes in a single-quoted string) and there's no clean way to expand ${FOLDER} on the local computer. These are solvable with mixed quoting, but it's messy.

Finally, when you use the variable, you should enclose it in double-quotes:

ssh -t user@server "$RM_CMD"

... this shouldn't matter in this particular case, but there are all sorts of things that can go wrong with non-double-quoted variable references, so it's generally a good practice to double-quote 'em.

2

You can check common errors in bash scripts with ShellCheck, which works online but is also available as an offline program. It supports different shells (identified by shebang) and gives also stylistik warnings (like in your case to use $(...) instead of backticks. You can also live-edit your pasted code and look how it is rated (helpful in combination with normal tutorials on coding style).

  • Thank you so much! Didn't knew about this, it's so useful! – Thin_icE Sep 30 '16 at 11:18
  • Also it is one example of useful and practical software written in Haskell, if you ever find yourself in need of arguments for that. ;) – user121391 Sep 30 '16 at 11:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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