Luke Hartt
Luke Hartt

Reputation: 1

Replacing characters in a sh script

I am writing an sh script and need to replace the . and - with a _

Current:

V123_45_678_910.11_1213-1415.sh

Wanted:

V123_45_678_910_11_1213_1415.sh

I have used a few mv commands, but I am having trouble.

for file in /virtualun/rest/scripts/IOL_Extra/*.sh ; do mv $file ${file//V15_IOL_NVMe_01./V15_IOL_NVMe_01_} ; done

Upvotes: 0

Views: 144

Answers (4)

Carlo Corradini
Carlo Corradini

Reputation: 3425

This should work:

#!/usr/bin/env sh

# Fail on error
set -o errexit
# Disable undefined variable reference
set -o nounset
# Enable wildcard character expansion
set +o noglob

# ================
# CONFIGURATION
# ================
# Pattern
PATTERN="/virtualun/rest/scripts/IOL_Extra/*.sh"

# ================
# LOGGER
# ================
# Fatal log message
fatal() {
  printf '[FATAL] %s\n' "$@" >&2
  exit 1
}

# Info log message
info() {
  printf '[INFO ] %s\n' "$@"
}

# ================
# MAIN
# ================
{
  # Check directory exists
  [ -d "$(dirname "$PATTERN")" ] || fatal "Directory '$PATTERN' does not exists"

  for _file in $PATTERN; do
    # Skip if not file
    [ -f "$_file" ] || continue

    info "Analyzing file '$_file'"

    # File data
    _file_dirname=$(dirname -- "$_file")
    _file_basename=$(basename -- "$_file")
    _file_name="${_file_basename%.*}"
    _file_extension=
    case $_file_basename in
      *.*) _file_extension=".${_file_basename##*.}" ;;
    esac

    # New file name
    _new_file_name=$(printf '%s\n' "$_file_name" | sed 's/[\.\-][\.\-]*/_/g')

    # Skip if equals
    [ "$_file_name" != "$_new_file_name" ] || continue

    # New file
    _new_file="$_file_dirname/${_new_file_name}${_file_extension}"

    # Rename
    info "Renaming file '$_file' to '$_new_file'"
    mv -i -- "$_file" "$_new_file"
  done
}

Upvotes: 1

atkr
atkr

Reputation: 56

I prefer using sed substitute as posted by oliv.
However, if you have not familiar with regular expression, using rename is faster/easier to understand:

Example:

$ touch V123_45_678_910.11_1213-1415.sh
$ rename -va '.' '_' *sh
`V123_45_678_910.11_1213-1415.sh' -> `V123_45_678_910_11_1213-1415_sh'
$ rename -va '-' '_' *sh
`V123_45_678_910_11_1213-1415_sh' -> `V123_45_678_910_11_1213_1415_sh'
$ rename -vl '_sh' '.sh' *sh
`V123_45_678_910_11_1213_1415_sh' -> V123_45_678_910_11_1213_1415.sh'
$ ls *sh
V123_45_678_910_11_1213_1415.sh

Options explained:
-v prints the name of the file before -> after the operation
-a replaces all occurrences of the first argument with the second argument
-l replaces the last occurrence of the first argument with the second argument

Note that this might not be suitable depending on the other files you have in the given directory that would match *sh and that you do NOT want to rename.

Upvotes: 0

chepner
chepner

Reputation: 531075

You don't need to match any of the other parts of the file name, just the characters you want to replace. To avoid turning foo.sh into foo-sh, remove the extension first, then add it back to the result of the replacement.

for file in /virtualun/rest/scripts/IOL_Extra/*.sh ; do
   base=${file%.sh}
   mv -i -- "$file" "${base//[-.]/_}".sh
done

Use the -i option to make sure you don't inadvertently replace one file with another when the modified names coincide.

Upvotes: 1

oliv
oliv

Reputation: 13249

You can try this:

for f in /virtualun/rest/scripts/IOL_Extra/*.sh; do
   mv "$f" $(sed 's/[.-]/_/g' <<< "$f")
done

The sed command is replacing all characters .- by _.

Upvotes: 0

Related Questions