Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

sed does not what I expect it to do

Tags:

linux

bash

sed

I want to do simple string replacements with sed to rename some files. Unfortunately it does not work the way I expect. My Input (these files):

'Djrum - Under Tangled Silence - 01 A Tune For Us.flac'
'Djrum - Under Tangled Silence - 02 Waxcap.flac'
'Djrum - Under Tangled Silence - 03 Unweaving.flac'
"Djrum - Under Tangled Silence - 04 L'Ancienne.flac"
'Djrum - Under Tangled Silence - 05 Hold.flac'
'Djrum - Under Tangled Silence - 06 Galaxy In Silence.flac'
'Djrum - Under Tangled Silence - 07 Reprise.flac'
'Djrum - Under Tangled Silence - 08 Three Foxes Chasing Each Other.flac'
'Djrum - Under Tangled Silence - 09 Let Me.flac'
'Djrum - Under Tangled Silence - 10 Out Of Dust.flac'
'Djrum - Under Tangled Silence - 11 Sycamore.flac'

My command:

for file in *.flac ; do a=(` echo "$file" | sed -rE 's/Djrum - Under Tangled Silence - // ; s/ /./ ' `) ; echo mv  "$file" "$a" ; done

My output:

mv Djrum - Under Tangled Silence - 01 A Tune For Us.flac 01.A # stuff missing
mv Djrum - Under Tangled Silence - 02 Waxcap.flac 02.Waxcap.flac
mv Djrum - Under Tangled Silence - 03 Unweaving.flac 03.Unweaving.flac
mv Djrum - Under Tangled Silence - 04 L'Ancienne.flac 04.L'Ancienne.flac
mv Djrum - Under Tangled Silence - 05 Hold.flac 05.Hold.flac
mv Djrum - Under Tangled Silence - 06 Galaxy In Silence.flac 06.Galaxy # stuff missing
mv Djrum - Under Tangled Silence - 07 Reprise.flac 07.Reprise.flac
mv Djrum - Under Tangled Silence - 08 Three Foxes Chasing Each Other.flac 08.Three # stuff missing
mv Djrum - Under Tangled Silence - 09 Let Me.flac 09.Let # stuff missing
mv Djrum - Under Tangled Silence - 10 Out Of Dust.flac 10.Out # stuff missing
mv Djrum - Under Tangled Silence - 11 Sycamore.flac 11.Sycamore.flac

Note the 1st, 8th, 9th and 10th result.

What I want to have is just [tracknumber].[title].flac.

I tried it on this site: https://sed.js.org/, where I get the correct results. What am I doing wrong?

like image 304
exocortex Avatar asked Jan 25 '26 22:01

exocortex


2 Answers

See @jhnc's complete explanations of why your script did not do what you expect

Here is a commented version that might be close to what you expected:

#!/usr/bin/env bash
# Rename .flac files by removing a fixed prefix and replacing spaces with dots.

# Avoid treating literal '*.flac' when no match is found (skip loop if no files)
shopt -s nullglob

for file in *.flac; do
  # Remove the fixed prefix
  a=${file#Djrum - Under Tangled Silence - }

  # Replace spaces with dots
  a=${a// /.}

  # If the filename changed and no file with the new name exists
  if ! [ "$a" = "$file" ] && ! [ -e "$a" ]; then
    mv -- "$file" "$a"
  fi
done
like image 179
Léa Gris Avatar answered Jan 28 '26 16:01

Léa Gris


Your code includes:

a=(` echo "$file" | sed -rE 's/Djrum - Under Tangled Silence - // ; s/ /./ ' `)

which does not do what you probably intend.

It says:

  • `...` - run commands in a subshell and return stdout as a string
  • a=(...) - assign the words in ... as the elements of array a
    • by default, words are delimited by whitespace, so a will contain multiple elements if ... contains unquoted whitespace

Note that if a is an array, referring to $a is the same as referring to ${a[0]}

Consider:

$ x=(`echo "a  b  c"`)
$ declare -p x
declare -a x=([0]="a" [1]="b" [2]="c")
$ echo $x
a
$

To fix your problem, quote the output of command. Better yet, don't use an array:

$ y=("`echo "a  b  c"`")
$ declare -p y
declare -a y=([0]="a  b  c")
$ z=`echo "a  b  c"`
$ declare -p z
declare -- z="a  b  c"
$

You may want to use s/ /./g or s/[[:space:]]/./g so that all spaces are converted and not just the first.

like image 38
jhnc Avatar answered Jan 28 '26 16:01

jhnc