0

I try to name a file with rows count in a crontab :

* * * * * ~/script > "~/targetfile-$(rows-count).csv"

I can do :

* * * * * ~/script > "~/targetfile-$(~/script | wc -l).csv"

But I think I can do much better and not execute script twice.

Can you help me ? Thx

0

2 Answers 2

2

Here, you could tell cron to use zsh to interpret the command line and do:

SHELL=/bin/zsh
* * * * * TMPPREFIX=~/.; (){ mv -- $1 ~/targetfile-$(($(wc -l < $1))).csv; } =(~/script)

That is use the =(...) form of process substitution to store the output of the script in a tempfile (as a hidden file in ~ instead of /tmp so the mv just does a rename), here passed as an argument to an anonymous function which renames it to the target file name.

Or to feed the output of the script to both the tempfile and wc -l at the same time:

SHELL=/bin/zsh
* * * * * TMPPREFIX=~/.; (){ ~/script >&1 > $1 | wc -l | read n; mv -- $1 ~/targetfile-$n.csv; } =(:)
1
  • 1
    Elegant solution (+1), I keep it for later, when I will learn zsh Commented Aug 28, 2021 at 8:16
1

Write the output of your script to a temporary file, count the number of lines in that file and move the file to a new name:

t=$(mktemp) && len=$("$HOME/script" | tee -- "$t" | wc -l) && mv -- "$t" "$HOME/targetfile-$len.csv"

If you are not using GNU wc, you may get whitespace characters at the start or end of the value in $len. You would then need to strip these out:

t=$(mktemp) && len=$("$HOME/script" | tee -- "$t" | wc -l) && mv -- "$t" "$HOME/targetfile-$(( len + 0 )).csv"

I run "$HOME/script" only once here and save the output to a temporary file ($t) and, at the same time (courtesy of tee for duplicating the data), count the number of lines in the output. The temporary file is then moved to the new name.

I would probably put this in a separate script and schedule that, rather than scheduling that whole list in my crontab.

The script could look like

#!/bin/sh

tmpfile=$(mktemp) &&
length=$("$HOME/script" | tee -- "$tmpfile" | wc -l) &&
mv -- "$tmpfile" "$HOME/targetfile-$(( length + 0 )).csv"
5
  • 2
    Note that some wc implementations add blanks before and after the number, so your ${length##*[[:blank:]]} would expand to nothing there. A common idiom to avoid issues with those blanks is to use $(( $(wc -l) )) (or $(( $(wc -l) +0 )) to still get 0 with those shells where $(( $empty )) doesn't do it already). Commented Aug 28, 2021 at 6:48
  • @StéphaneChazelas Ouch. Thanks! Commented Aug 28, 2021 at 6:51
  • 2
    The +0 would not be needed in $(( len + 0 )) as $((len)) is required to expand to 0 if $len is empty and anyway $(( len )) by itself is valid syntax. But $(( len )) when $len is not a decimal number is unspecified per POSIX and wouldn't work in bosh for instance with len=" 1 ". $(( $len + 0 )) is fine as the $len is expanded first and $(( 1 +0 )) (or $(( +0 )) when $len is empty are valid syntax. I'd do len=$(( $(wc -l...) +0 )) here. Though with ... | wc -l as opposed to wc -l < ..., the output is unlikely to be empty and the +0 could be omitted. Commented Aug 28, 2021 at 7:49
  • Great, mktemp and tee were the key. Is there a reason to use -- with mv ? Commented Aug 28, 2021 at 8:21
  • 1
    @JCH77 It's just a precaution in the very unlikely event that $t starts with a dash. Note that I forgot this with tee (fixed now). Commented Aug 28, 2021 at 8:31

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.