5

I want to run wc -l and use the result in an arithmetic expansion. In other words, I want to do something like this:

wc -l (now somehow pipe/pass the result of this to) $((2 + result of wc command))

How can I do this?

Context

In my ~/Pictures directory, I have multiple files named "Screenshot from YYYY-MM-DD hh-mm-ss.png", as well as other files. I want to keep all files that are not Screenshots, and only a specified number of Screenshot pictures, based on how recent they were. I want to basically only keep the last 3 most recent Screenshots I have, and delete all the rest.

So here is what I have so far:

ls | grep "Screenshot *" | sort -r | wc -l

What I then wanted to do was to subtract 3 from wc -l, which would then allow me to use tail to list all the files that are not the first 3, and then just delete them.

Pablo Bianchi
  • 17,371

2 Answers2

2

Assuming FILE is a file that is located in the current directory:

echo $((`wc -l < FILE`+2))  

wc -l < FILE returns the number of lines in FILE and echo $((&grave;wc -l < FILE&grave; +2)) returns the number of lines in FILE + 2.

Translating a string into a numerical expression is relatively straightforward using arithmetic expansion of the form $((EXPRESSION)) where EXPRESSION is an arithmetic expression.

karel
  • 122,292
  • 133
  • 301
  • 332
2

For what you are asking (source):

cat FILE | wc -l | xargs -n 1 bash -c 'echo $(($1 + 2))' args

bash -c 'commands' run a new bash environment, where $1 is an argument given by xargs. Use man the_commmand to access manual pages and learn more about each command and their options.

From man bash:

SYNOPSIS
xargs [options] [command [initial-arguments]]

OPTIONS
-c If the -c option is present, then commands are read from the first non-option argument command_string. If there are arguments after the command_string, the first argument is assigned to $0 and any remaining arguments are assigned to the positional parameters. The assignment to $0 sets the name of the shell, which is used in warning and error messages.

$ bash -c 'echo $1' aaa bbb ccc
bbb
$ bash -c 'echo $0' aaa bbb ccc
aaa
$ echo $0
/bin/bash

So in this case you could avoid using the placeholder args (note you can use any word) just using $0 instead. Also, for just wc -l you can avoid the -n 1:

cat FILE | wc -l | xargs bash -c 'echo $(($0 + 2))'

For what you need might be more suitable to remove interactively (-i) files older than eg 20 days.

find ~/Pictures/ -type f -name "Screenshot*" -mtime +20 -exec rm -i {} +

To get the first 3 newest files with that name pattern is more simple:

ls -lt ~/Pictures/Screenshot* | head -n 3
Pablo Bianchi
  • 17,371