Home > Enterprise >  Bash script MV is disappearing files
Bash script MV is disappearing files

Time:02-02

I've written a script to go through all the files in the directory the script is located in, identify if a file name contains a certain string and then modify the filename. When I run this script, the files that are supposed to be modified are disappearing. It appears my usage of the mv command is incorrect and the files are likely going to an unknown directory.

#!/bin/bash

string_contains="dummy_axial_y_position"
string_dontwant="dummy_axial_y_position_time"
file_extension=".csv"

for FILE in *
do
    if [[ "$FILE" == *"$string_contains"* ]];then
            if [[ "$FILE" != *"$string_dontwant"* ]];then
                 filename= echo $FILE | head -c 15
                 combined_name="$filename$file_extension"
                 echo $combined_name
                 mv $FILE $combined_name
                 echo $FILE
                 
            fi
    fi
done

I've done my best to go through the possible errors I've made in the MV command but I haven't had any success so far.

CodePudding user response:

The issue is with the filename assignment line:

filename= echo $FILE | head -c 15

This should be written as:

filename=$(echo "$FILE" | head -c 15)

The incorrect line is assigning the output of echo to the variable filename, instead of the result of the head command.

Additionally, you might want to add the -v option to the mv command to have it verbosely show what it is doing:

mv -v $FILE $combined_name

CodePudding user response:

There are a couple of problems and several places where your script can be improved.


filename= echo $FILE | head -c 15

This pipeline runs echo $FILE adding the variable filename having the null string as value in its environment. This value of the variable is visible only to the echo command, the variable is not set in the current shell. echo does not care about it anyway.

You probably want to capture the output of echo $FILE | head -c 15 into the variable filename but this is not the way to do it.
You need to use command substitution for this purpose:

filename=$(echo $FILE | head -c 15)

head -c outputs only the first 15 characters of the input file (they can be on multiple lines but this does not happen here). head is not the most appropriate way for this. Use cut -c-15 instead.
But for what you need (extract the first 15 characters of the value stored in the variable $FILE), there is a much simpler way; use a form of parameter expansion called "substring expansion":

filename=${FILE:0:15}

mv $FILE $combined_name

Before running mv, the variables $FILE and $combined_name are expanded (it is called "parameter expansion"). This means that the variable are replaced by their values.

For example, if the value of FILE is abc def and the value of combined_name is mnp opq, the line above becomes:

mv abc def mnp opq

The mv command receives 4 arguments and it attempts to move the files denoted by the first three arguments into the directory denoted by the fourth argument (and it probably fails).

In order to keep the values of the variables as single words (if they contain spaces), always enclose them in double quotes. The correct command is:

mv "$FILE" "$combined_name"

This way, in the example above, the command becomes:

mv "abc def" "mnp opq"

... and mv is invoked with two arguments: abc def and mnp opq.


combined_name="$filename$file_extension"

There isn't any problem in this line. The quotes are simply not needed.
The variables filename and file_extension are expanded (replaced by their values) but on assignments word splitting is not applied. The value resulted after the replacement is the value assigned to variable combined_name, even if it contains spaces or other word separator characters (spaces, tabs, newlines).


The quotes are also not needed here because the values do not contain spaces or other characters that are special in the command line. They must be quoted if they contain such characters.

string_contains="dummy_axial_y_position"
string_dontwant="dummy_axial_y_position_time"
file_extension=".csv"

It is not not incorrect to quote the values though.


for FILE in *
do
    if [[ "$FILE" == *"$string_contains"* ]];then
        if [[ "$FILE" != *"$string_dontwant"* ]]; then

This is also not wrong but it is inefficient.
You can use the expression from the if condition directly in the for statement (and get rid of the if statement):

for FILE in *"$string_contains"*; do
    if [[ "$FILE" != *"$string_dontwant"* ]]; then
    ...

If you have read and understood the above (and some of the linked documentation) you will be able to figure out yourself where were your files moved :-)

  •  Tags:  
  • bash
  • Related