Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I am writing a script to move files into directories based on the filename. Files have yyyyddmm-xxxxxxx.jpg name format. The desired directory structure is in the format 2013/01 Jan/31. I am unable to get date to format correctly with a space between month number and month name. When I try to use +%Y/%m %b format, I get this error message:

date: extra operand `%b"'

I tried double and single quotation marks, but to no avail. However, date +"%Y/%m %b/%d" works fine in sh:

2013/10/27 Oct

Also, is there a better way to generate the directory name than using MOVEDIRSTR and MOVEDIR variables (see script)?

Here's my current script:

FLIST=`ls "$IMGDIR" | grep -E '^.*\.jpg$'`

# If there are files to move
if [ -n "${FLIST}" ]; then
    # For each file
    while read -r line; do
        # Parse filename to YYYY/mm Mmm/Dd
        echo $line
        MOVEDIRSTR=`sed -r -e 's:([0-9]{4})([0-9]{2})([0-9]{2}).*:date -d \1-\2-\3 +%Y/%m_%b/%d:' <<< "$line"`
        MOVEDIR=`$MOVEDIRSTR`

        # If a directory does not exist, create it
        [ -d "$ARCHIVEDIR/$MOVEDIR" ] || (mkdir -p "$ARCHIVEDIR/$MOVEDIR")

        # Move file into YYYY/mm Mmm directory
        # mv -f "$IMGDIR/$line" "$ARCHIVEDIR/$MOVEDIR"
    done <<< "$FLIST"
fi
share|improve this question

3 Answers 3

You have to quote the format to date after the + sign.

$ date +"%Y/%m %b"
2013/10 Oct

Regarding the variables. $MOVEDIRSTR seems unecessary.

MOVEDIR=$(sed -r -e 's:([0-9]{4})([0-9]{2})([0-9]{2}).*:date -d \1-\2-\3 +%Y/%m_%b/%d:' <<< "$line")

Since with $FLIST you're parsing out the dates from that directory, I don't see a cleaner way.

UPDATE #1

Given the OP's feedback in the comments below, he's using a QNAP device and so likely has a watered down version of these commands provided by BusyBox. If you look at the date command like so: ls -l /bin/date it's probably a link to an executable called busybox or something similar. These commands aren't full-featured, hence your problems.

He confirmed this:

You're probably right. My date is its own executable, but /bin/sed -> busybox

Given the limitations the methods discussed above may not work since you're working with a limited set of features with these tools.

share|improve this answer
    
Quotation marks are not working for me for some reason. sh expands the date format as '+"%Y/%m' '%b/%d"'. Also, for some reason $() is not working and sh tries to execute =date, which does not exist. Here's the output I get when I try your suggested code: +++ sed -r -e 's:([0-9]{4})([0-9]{2})([0-9]{2}).*:date -d \1-\2-\3 +"%Y/%m %b/%d":' ++ =date -d 2013-10-27 '+"%Y/%m' '%b/%d"' ./dvrsnapshots.sh: line 25: =date: command not found + –  Serge Oct 27 '13 at 5:56
    
@Serge - I had a typo with the setting of the variable. Please retry. Also are you using sh or bash? You tagged the Q as bash. –  slm Oct 27 '13 at 6:06
    
I simplified MOVEDIRSTR to: MOVEDIR=$(sed -r -e 's:([0-9]{4})([0-9]{2})([0-9]{2}).*:date -d \1-\2-\3 +"%Y/%m_%b/%d":' <<< "$line") It was necessary to keep tildas inside $(). Still no luck with date formatting though. –  Serge Oct 27 '13 at 6:21
    
I'm running /bin/sh on a QNAP device. –  Serge Oct 27 '13 at 6:24
    
@Serge - you're likely using a watered down version of these commands provided by BusyBox. If you look at the date command like so: ls -l /bin/date it's probably a link to an executable called busybox or something similar. These commands aren't full-featured, hence your problems. –  slm Oct 27 '13 at 6:27

First of all, I would use a glob to avoid parsing ls and obtaining the list of .jpg files in that roundabout way. Second, you can use the shell itself (no need for sed) to extract the date components:

shopt -s nullglob
for file in "$IMGDIR"/*.jpg; do
    file_name="$(basename file)"
    printf "%s\n" "$file_name"
    numbers="${file%-*}"
    year="${numbers%[0-9][0-9][0-9][0-9]}"
    monthday="${numbers#[0-9][0-9][0-9][0-9]}"
    month="${monthday%[0-9][0-9]}"
    day="${monthday#[0-9][0-9]}"
    movedir="$(date -d "$year-$month-$day" +"%Y/%m %b/)"
    movefile="$(date -d "$year-$month-$day" +"%Y/%m %b/%d)"
    [ -d "$ARCHIVEDIR/$movedir" ] || mkdir -p "$ARCHIVEDIR/$movedir"
    mv "$file" "$movefile"
done

This assumes of course that your date command has a full enough feature set, since you mentioned it is a separate executable from BusyBox. It will also break if your date string is not exactly 8 digits long.

share|improve this answer

see if the following could solve the date extraction and formatting part:

$ f=20130131-abcdefgh.jpg
$ [[ $f =~ ^([[:digit:]]{4})([[:digit:]]{2})([[:digit:]]{2}) ]]
$ yyyy=${BASH_REMATCH[1]}
$ mm=${BASH_REMATCH[2]}
$ dd=${BASH_REMATCH[3]}
$ date -d ${yyyy}-${mm}-${dd} +'%Y/%m %b/%d'
2013/01 Jan/31
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.