Home > Software engineering >  Looping through filenames in bashscript - need to update a line of text in a file on each loop nth i
Looping through filenames in bashscript - need to update a line of text in a file on each loop nth i

Time:10-30

I am trying to pad a series of wav files with silence at the beginning and end using ffmpeg.

the line of code for this i gleaned from elsewhere on this amazing site:

ffmpeg -f concat -i input.txt -codec copy output.wav

where input.txt is simply a list of 3 filenames: silence.wav 0.wav silence.wav

indicating what is to be concatenated

I can do this for an individual file and then update line 2 manually, but there are 1000 files. They are named 0.wav 1.wav 2.wav.

I figure this is trivial in a loop:

COUNTER=1
for FILE in *.wav
do
        ffmpeg -f concat -i input.txt -codec copy $FILE
        echo $FILE
        echo $COUNTER
        sed -i "2s/.*/file \'${COUNTER}.wav\'/" input.txt
        ((COUNTER=COUNTER 1))
done

However the loop doesn't iterate sequentially 0.wav 1.wav 2.wav - rather more erratically (0.wav, 10.wav, 11.wav) - so my counter is out of sync. and my saved filenames are not aligned with their original filenames.

Is there a work around that strips the name from the file itself rather than relying on a counter?

CodePudding user response:

If the counter is already contained in the file name, why not just reuse the file name? That would avoid the issue with string sorting (in which "11" < "9") versus numerical sorting (in which 11 > 9) and it would also work fine if the file names (numbers) were sparse. Also, the output file should not be the same file as one of the inputs. (It might be the case that ffmpeg can handle it gracefully using temporary files, bu I wouldn’t bet on that.)

for file in *.wav; do
  sed -i "2s/.*/file \'${file}\'/" input.txt
  ffmpeg -f concat -i input.txt -codec copy "output-${file}"
  mv "output-${file}" "$file"  # replaces original file!
done

CodePudding user response:

The main problem with your setup is that you read your files in alphabetical order. so after 1.wav comes 10.wav.

Your code then becomes:

ffmpeg -f concat -i input.txt -codec copy 10.wav
sed -i "2s/.*/file \'2.wav\'/" input.txt

so ffmpeg works with 10.wav, while you replace something about 2.wav in input.txt.

Looks like you loop through your files in alphabetical order.

Maybe you could do something like this to loop over your files:

COUNTER=1
while [ $COUNTER -le 1000 ]
do
  echo "Filename: ${COUNTER}.wav"
  ((COUNTER=COUNTER 1))
done

I don't know if ffmpeg starts a new process, but the loop might start ffmpeg, but not waiting till it is finished. This way you could end up with 1000 ffmpeg processes running at the same time.

CodePudding user response:

You should try replacing

for FILE in *.wav

with

for FILE in $(ls *.wav | sort -t '.' -k 1 -n)

Let me know if it worked.

  • Related