Depending on what you are trying to achieve and what is your current knowledge, you can take different approaches.
If you are trying to learn OpenGL 2.0 while also learning GLSL, I suggest getting the Red book and the Orange book as a set, as they go hand in hand.
If you want a less comprehensive guide that will just get you started, check out the OpenGL bible.
If I misunderstood your question and you already know OpenGL, and want to study more about GLSL in particular, here's a good phong shading example that shows the basics.
Compiling a shader source is really simple,
First you need to allocate a shader slot for your source, just like you allocate a texture, using glCreateShader:
GLuint vtxShader = glCreateShader(GL_VERTEX_SHADER);
GLuint pxlShader = glCreateShader(GL_FRAGMENT_SHADER);
After that you need to load your source code somehow. Since this is really a platform dependent solution, this is up to you.
After obtaining the source, you set it using glShaderSource:
glShaderSource(vtxShader, 1, &vsSource, 0);
glShaderSource(pxlShader, 1, &psSource, 0);
Then you compile your sources with glCompileShader:
Link the shaders to each other, first allocate a program using glCreateProgram, attach the shaders into the program using glAttachShader, and link them using glLinkProgram:
GLuint shaderId = glCreateProgram();
Then, just like a texture, you bind it to the current rendering stage using glUseProgram:
To unbind it, use an id of 0 or another shader ID.
And that's mostly everything to it, you can use the glUniform function family alongside with glGetUniform to set parameters as well.
Your question is a little broad, as you can literally write an entire book on how to create custom shaders, but it's a commonly asked one, so I can at least point people in the right direction.
Filters in GPUImage are written in the OpenGL Shading Language (GLSL). There are slight differences between the OpenGL targets (Mac, desktop Linux) and OpenGL ES ones (iOS, embedded Linux) in that shaders on the latter use precision qualifiers that are missing on the former. Beyond that, the syntax is the same.
Shader programs are composed of a matched pair of a vertex shader and a fragment shader. A vertex shader operates over each vertex and usually handles geometric manipulations. A fragment shader operates over each fragment (pixel, generally) and calculates the color to be output to the screen at that fragment.
GPUImage deals with image processing, so most of the time you'll be working only with fragment shaders and relying on one of the stock vertex shaders. The above is an example of a fragment shader that takes in each pixel of an input texture (the image from the previous step in the processing pipeline), manipulates its color values, and writes out the result to the gl_FragColor builtin.
The first line in the main() function:
lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
uses the texture2D() function to read the pixel color in the inputImageTexture at a given coordinate (passed in from the vertex shader in the first stage). These coordinates are normalized to the 0.0-1.0 range, and therefore are independent of the input image size.
The values are loaded into a vector type (vec4) that contains multiple components within a single type. In this case, the color components for red, green, blue, and alpha are stored in this four-component vector and can be accessed via .r, .g, .b, and .a. The color component values are also normalized to the 0.0-1.0 range, in case you're used to working with 0-255 values.
In the particular case of a sepia tone filter, I'm attempting to apply a well-known color matrix for a sepia tone effect to convert the incoming color to an outgoing one. That requires matrix multiplication, which I do explicitly in the code above. In the actual framework, this is done as matrix math using builtin types within the shader.
There are many, many ways to manipulate colors to achieve certain effects. The GPUImage framework is full of them, based largely on things like color conversion standards published by Adobe or other organizations. For a given effect, you should identify if one of these existing implementations will do what you want before setting out to write your own.
If you do want to write your own, first figure out the math required to translate incoming colors into whatever output you want. Once you have that, writing the shader code is easy.
The lookup filter in GPUImage takes another approach, and that's to start with a lookup image that you manipulate in Photoshop under the filter conditions you wish to mimic. You then take that filtered lookup image and attach it to the lookup filter. It translates between the incoming colors and their equivalents in the lookup to provide arbitrary color manipulation.
Once you have your shader, you can create a new filter around that in a few different ways. I should say that my new GPUImage 2 framework greatly simplifies that process, if you're willing to forgo some backwards compatibility.
The 5th edition of OpenGL SuperBible has been recently released. This edition reflects OpenGL 3.3 which was released at the same time as OpenGL 4.0, the book only covers the core profile and assumes no prior OpenGL knowledge.
That's what I got from the book's description anyway. I have the 4th edition and it's an excellent resource for OpenGL 2.0, so I assume the new edition along with the latest OpenGL Shading Language book would be just what you're looking for.
Durian Software has an ongoing series of tutorials covering modern OpenGL. They are aimed at OpenGL 2.0 but avoid using any deprecated functionality in later versions.