I've a bunch of files that should be renamed programatically in order to be comprehensible by the application.

They have this formatting : Files to be renamed

I need to cut from the end until the first _ and replace it by a dot(.).

As I don't know per advance the length of the filename neither the numbers of _ in the filename, do you have any idea trough awk/sed/cut ?

for F in *_*; do echo mv -- "${F}" "${F%_*}.${F##*_}"; done

If the output looks correct then remove the echo command from above.

The trick is that ${F%_*} removes last _26 and ${F##*_} removes everything before the last _. Try these commands to see how it works. The delimiter is now ::

echo "${PATH}"
echo "${PATH%:*}"
echo "${PATH##*:}"
echo "${PATH%:*}_${PATH##*:}"
  • you add <!-- language: lang-none --> before your codeblock to turn off syntax highlighting... – don_crissti Oct 3 '16 at 16:43
  • Hello hschou, Thanks it works like a charm ! – admstg Oct 3 '16 at 16:48

Using sed

for file in *_*
    echo mv $file $( sed 's/\(.*\)_/\1\./' <<< $file)

Remove the echo if you're satisfied.

  • sed makes it slow. For each file you have to start a new process and that takes time. One should always try to use internal bash-commands. – hschou Oct 3 '16 at 19:20
  • @hschou I agree that the bash solution is the most efficient however he asked for solutions using sed or awk. – Zachary Brady Oct 3 '16 at 19:24

You can replace the last block with sed, using the end of line marker ($).

for file in *_* ; do
  #any alphanumeric string as suffix
  mv $file $( sed 's/_\([A-Za-z0-9]\{1,\}\)$/.\1/' <<< $file )
  #alternatively numbers only as in given input sample
  mv $file $( sed 's/_\([0-9]\{1,\}\)$/.\1/' <<< $file )

AFAIK the \{1,\} bit as "one or more" of the preceding list is GNU sed - but I'm not 100% sure of this restriction.

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.