These are the file sizes in my current directory. I got them using the command:

ls -l | tr -s " " | cut -d " " -f5 | tail +2

Is there anyway that I can add all 15 of these sizes to get the total size of all the files using ONLY cut, echo, eval, head, ls, tail, tr commands


From that list of commands, none of them can add up numbers, so I suppose the idea is that the shell's arithmetic expansions have to be used.

Something like:

echo "$(($(LC_ALL=C ls -nq | tr -s ' ' | cut -d ' ' -f5 | tail -n +2 | tr '\n' +)0))"

(here assuming none of the files are devices files for which the ls -l output doesn't have the size in 5th column but the device major number).

Note that the output of ls -l or ls -n varies between locales and is unspecified in locales other than C/POSIX.

Also, without -q, it wouldn't work for files whose name or symlink target contains newline characters.

Not using -q would amount to an arbitrary command injection vulnerability would you run the command in a directory where someone could create files with malicious names (try for instance after running ln -s $'\nx x x x a[$(reboot)0]' x without the -q)

You'd want -n instead of -l as with -l you get user/group names instead of ids which may contain space characters.

Note that tail +2 is deprecated. The standard syntax is tail -n +2.


Put your numbers in a file called "file.txt", then

var=$(cat file.txt)
echo $((${var//$'\n'/+}))

Basically, the pattern in the arrhythmic expression is in the form: ${parameter//find/replace}, or in our example ${var// /+}. This is Bash parameter expansion:

- `\n` will add blank spaces between the numbers in the list
- The double slashes `//` are for replacing all occurrences of space with `+` sign, if you put one slash `/`, only first space is going to be replaced. The space is there because you are replacing space with plus sign.

The previous solution can be simplified as follows:

var=echo $(< file.txt)
echo $((${var// /+}))

However, both solutions suffer from command substitutions which may trim trailing newlines

More here

  • 1
    Ooh, I hadn't though of bash substitutions. Does this handle trailing newlines? – Cyclic3 Oct 2 '18 at 19:45
  • 1
    the $(...) command substitutions will trim trailing newlines: gnu.org/software/bash/manual/bashref.html#Command-Substitution – glenn jackman Oct 2 '18 at 19:50
  • 1
    @goro, that is fiendishly clever. I'm upvoting, but I feel a bit guilty doing it. – glenn jackman Oct 2 '18 at 19:51
  • 1
    Upvoted for using a single external command to do this. Could you maybe add a bit of description to the script so that vistors could learn from it? – Cyclic3 Oct 2 '18 at 19:55
  • 1
    You don't even need to call out to cat: contents=$(< file.txt) is pure bash. – glenn jackman Oct 2 '18 at 21:08

Using paste and bc :

$ paste -sd + file | bc
  • OP did say using ONLY cut, echo, eval, head, ls, tail, tr commands – Cyclic3 Oct 2 '18 at 19:40
  • 2
    Me said that ls is not a tool to be parsed ^^ – Gilles Quenot Oct 2 '18 at 19:41
  • Yes, but unfortunately this is the question we have been given. It is not an ideal situation, but these are the constraints we have, and we have to work within them. – Cyclic3 Oct 2 '18 at 19:42
  • 1
    Note that POSIX paste requires at least one filename argument, so portably, you'd want paste -sd + file or paste -sd + - < file. Note that -l is not necessary here. – Stéphane Chazelas Oct 2 '18 at 20:13

Use bash's $(( )) for arithmetic:

for i in $(command to get sizes); do ACC=$((i + ACC)); done
echo $ACC
  • $ is not needed on ordinary variables in arithmetic context (inside $(( ... ))). – Kusalananda Oct 2 '18 at 20:46
  • @Kusalanda I didn't know that! I shall update the answer – Cyclic3 Oct 3 '18 at 7:14

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.