0

Question: Suppose there is a folder with files log1.txt, log2.txt, log3.txt, etc. I would like to find the smallest integer N such that log<N>.txt does not exist. Is there a simple command/way to achieve this?

Example: if the folder is empty, the command should return log1.txt. If the folder has log1.txt, log2.txt, the command should return log3.txt.

  • in the example that you gave, the smallest missing integer is 0 .... i think that you want next smallest integer – jsotola Jul 9 at 0:22
  • Sure. Either definition works for my question (positive or non-negative integers). – Zuza Jul 9 at 6:08
  • The "that does not exist" should apply to the file rather than to the folder. So perhaps "Find lowest numbered file name that does not exist in a folder". – roaima Jul 9 at 9:36
  • 1
    I've made a suggestion for a new title; feel free to further reword it to make it clearer to you! – Jeff Schaller Jul 9 at 11:09
3

As bash script:

#!/bin/bash
i=1
while [ -f "log${i}.txt" ]; do
  ((i++))
done
echo "log${i}.txt"

The while-loop increments variable $i as long as file log${i}.txt exists. The echo outputs the non-existing filename with the next number.

  • Very nice. It skirts the question a bit, but even touch log$((i++)).txt will work for now. Thanks. – Zuza Jul 9 at 6:00
2

This horrible pipeline will satisfy your requirement (concatenate the non-comment parts together to create an unreadable one-liner if you must).

Set up

touch log{1..13}.txt log{15..20}.txt

Find the first available item placement

( find log*.txt | sort -V; echo X ) |     # List the files and an extra one at the end
    nl |                                  # Add line-numbers
    tr -dc '[:digit:][:space:]' |         # Strip away non-numeric parts
    sed -r '/ ([1-9][0-9]*)\t\1$/d' |     # Delete lines with two matching numbers
    awk '{print $1; exit}'                # Print the the line number of the first remaining match

Output

14

If you then fill in the missing slot

touch log14.txt

Output

21

As an aside for other readers, if you can find a way to improve upon the tr | sed | awk construct, which is often indicative of a poorly written pipeline, I'd be interested to see what you suggest.

  • It's a one-liner, can't argue with that :) gj – Zuza Jul 9 at 6:06
  • "if you can find a way to improve upon the tr | sed | awk construct [...]": how about echo $(($(grep -Ec '([1-9][0-9]*)[[:blank:]]+[[:graph:]]+\1\.[[:graph:]]+$') + 1)) ? However, if you ended up using awk anyway, why not do everything with it and get rid of nl too ? your same algorithm (which I think it's clean and clever) might be like: awk -F '[^0-9]+' -- 'NR != $(NF-1) {print NR; exit}' ? – LL3 Jul 9 at 16:36

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.