HiveBrain v1.2.0
Get Started
← Back to all entries
patternbashMinor

Bash CGI Upload File

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
uploadfilebashcgi

Problem

I'm using the following Bash CGI to upload a file:

#!/bin/bash
echo "Content-Type: text/plain"
echo

if [ "$REQUEST_METHOD" = "POST" ]; then
    TMPOUT=hello
    cat >$TMPOUT

    # Get the line count
    LINES=$(wc -l $TMPOUT | cut -d ' ' -f 1)

    # Remove the first four lines
    tail -$((LINES - 4)) $TMPOUT >$TMPOUT.1

    # Remove the last line
    head -$((LINES - 5)) $TMPOUT.1 >$TMPOUT

    # Copy everything but the new last line to a temporary file
    head -$((LINES - 6)) $TMPOUT >$TMPOUT.1

    # Copy the new last line but remove trailing \r\n
    tail -1 $TMPOUT | tr -d '\r\n' >> $TMPOUT.1
fi


This is for a uClinux/Busybox server. When a file is passed this way, the original $TMPOUT will contain a four line head and one line tail that need to be removed to end up with the same file. The resulting file's hash is identical to the original.

It works but it seems pretty ugly, creating two files and such. I'm by no means a pro in bash, can this be made prettier?

Keep in mind that the target is a little embedded device and has no Perl/Python or anything on it. It needs to be pure bash.

Solution

Since your script has no content to return, a status code of 204 No Content would be more desirable than 200 Success. For that, you should echo "Status: 204 No Content" (RFC 3875 Sec 6.3.3). Also consider returning using status code 405 Method Not Allowed for anything other than a POST request.

$TMPOUT is a misnomer. The file is not temporary at all — $TMPOUT.1 contains the final output of your script.

If your goal is to redirect the input to a file, discarding the first four lines, the last line, and the trailing newline of the penultimate line, you don't need to execute any external commands. Bash is fully capable of doing all of the work itself. The script isn't pretty, but I still find it easier to understand than copying the data back and forth, extracting lines here and there each time.

#!/bin/bash

case "$REQUEST_METHOD" in
  POST)
    (
        # Discard first four lines
        read && read && read && read &&

        # Read and echo, buffering two lines
        read line1 &&
        read line2 &&
        while read nextline ; do
            echo "$line1"
            line1="$line2"
            line2="$nextline"
        done

        # Echo penultimate line with no trailing newline.
        echo -n "$line1"

        # Discard last line ($line2)
    ) > hello

    echo 'Status: 204 No Content'
    echo
    ;;

  *)
    echo 'Status: 405 Method Not Allowed'
    echo
esac

Code Snippets

#!/bin/bash

case "$REQUEST_METHOD" in
  POST)
    (
        # Discard first four lines
        read && read && read && read &&

        # Read and echo, buffering two lines
        read line1 &&
        read line2 &&
        while read nextline ; do
            echo "$line1"
            line1="$line2"
            line2="$nextline"
        done

        # Echo penultimate line with no trailing newline.
        echo -n "$line1"

        # Discard last line ($line2)
    ) > hello

    echo 'Status: 204 No Content'
    echo
    ;;

  *)
    echo 'Status: 405 Method Not Allowed'
    echo
esac

Context

StackExchange Code Review Q#79549, answer score: 5

Revisions (0)

No revisions yet.