Command line Twitter status update for Linux and Mac

This is my first Twitter updating script, written in BASH (shell script). It uses the CURL program (which is included in most systems).
The script will work with Linux, Mac OS X and also cygwin. My script can currently log in, post a new tweet and log out. But there are plenty of things you could do in between, like reading messages, sending private messages, reading tweets… If you have a feature request post it in the comments. And also don’t forget to post your own improvements! :)

Download: twitter-bot

Usage:

  • bash tweet.sh "My new tweet!"


And make sure that you:
- Enter a correct username and password,
- Have CURL with SSL support installed,
- Have read/write permissions in current directory.
- Run it with “bash” and not with “sh”.

#!/bin/bash
#Twitter status update bot by http://360percents.com
#Author: Luka Pusic <pusic93@gmail.com>

#REQUIRED PARAMS
username="username"
password="password"
tweet="$*" #must be less than 140 chars

#EXTRA OPTIONS
uagent="Mozilla/5.0" #user agent (fake a browser)
sleeptime=0 #add pause between requests

if [ $(echo "$tweet" | wc -c) -gt 140 ]; then
	echo "[FAIL] Tweet must not be longer than 140 chars!" && exit 1
elif [ "$tweet" == "" ]; then
	echo "[FAIL] Nothing to tweet. Enter your text as argument." && exit 1
fi

touch "cookie.txt" #create a temp. cookie file

#GRAB LOGIN TOKENS
echo "[+] Fetching twitter.com..." && sleep $sleeptime
initpage=$(curl -s -b "cookie.txt" -c "cookie.txt" -L --sslv3 -A "$uagent" "https://mobile.twitter.com/session/new")
token=$(echo "$initpage" | grep "authenticity_token" | sed -e 's/.*value="//' | sed -e 's/" \/>.*//')

#LOGIN
echo "[+] Submitting the login form..." && sleep $sleeptime
loginpage=$(curl -s -b "cookie.txt" -c "cookie.txt" -L --sslv3 -A "$uagent" -d "authenticity_token=$token&username=$username&password=$password" "https://mobile.twitter.com/session")

#GRAB COMPOSE TWEET TOKENS
echo "[+] Getting compose tweet page..." && sleep $sleeptime
composepage=$(curl -s -b "cookie.txt" -c "cookie.txt" -L -A "$uagent" "https://mobile.twitter.com/compose/tweet")

#TWEET
echo "[+] Posting a new tweet: $tweet..." && sleep $sleeptime
tweettoken=$(echo "$composepage" | grep "authenticity_token" | sed -e 's/.*value="//' | sed -e 's/" \/>.*//' | tail -n 1)
update=$(curl -s -b "cookie.txt" -c "cookie.txt" -L --sslv3 -A "$uagent" -d "authenticity_token=$tweettoken&tweet[text]=$tweet&tweet[display_coordinates]=false" "https://mobile.twitter.com/")

#GRAB LOGOUT TOKENS
logoutpage=$(curl -s -b "cookie.txt" -c "cookie.txt" -L --sslv3 -A "$uagent" "https://mobile.twitter.com/account")

#LOGOUT
echo "[+] Logging out..." && sleep $sleeptime
logouttoken=$(echo "$logoutpage" | grep "authenticity_token" | sed -e 's/.*value="//' | sed -e 's/" \/>.*//' | tail -n 1)
logout=$(curl -s -b "cookie.txt" -c "cookie.txt" -L --sslv3 -A "$uagent" -d "authenticity_token=$logouttoken" "https://mobile.twitter.com/session/destroy")

rm "cookie.txt"

86 thoughts on “Command line Twitter status update for Linux and Mac

  1. Actually my curl answered


    curl: option --ssl: is ambiguous

    until I changed both –ssl with –sslv3.

    Thanks for the script!

    Cheers

  2. Hi I’m getting this error message and can’t figure it out

    ./tweet.sh: line 30: unexpected EOF while looking for matching “’

    Even after I comment out line thirty, I get the same error message, (still in reference to line thirty).

    The only change I made was to change the variable called tweet to $1 allowing the string to be tweeted to be a parameter on the command line.
    Kurt

    • Are you running it with “bash” and not “sh”? Which bash version are you using? Looks like there is a missing quotation mark…

      The new version of the script above is accepting the tweet as $* parameters, so you can download that.

      Best regards

  3. Doesn’t work for me. It looks like it’s working and the command completes without error, but no message is tweeted.

  4. Maybe it’s a problem with certificates. Removed -s of the first curl line and got the error message:

    problem with the SSL CA cert (path? access rights?)

    Maybe it’s because I tested it from a linux box that has no web browser and has no twitter certificates.

  5. Curl version:

    curl 7.21.1 (arm-angstrom-linux-gnueabi) libcurl/7.21.1 GnuTLS/2.10.2 zlib/1.2.3
    Protocols: dict file ftp ftps http https imap imaps pop3 pop3s rtsp smtp smtps telnet tftp
    Features: Largefile NTLM SSL libz

    I have done some more tests. Curl fetches return nothing. if I add to the commands “-cacert mobile.twitter.com”, curl fetches retrieve data, but the command still completes without error but tweets nothing.

    If I get some time I’ll do some more tests.

  6. Thanks! Your session-based approach is much simpler than trying to muck around with OAuth!

    What kind of license are you posting this code under? I would like to include it in an open source project of mine, if possible, but I need your permission :)

  7. BTW, people having SSL certificate trouble: just add the -k switch to curl, to force it not to validate twitter’s certificate. Or if you’re really paranoid about someone poisoning your DNS and pretending to be twitter, you’ll have to find a Certificate Authority bundle that has the right signature somewhere in it (and whose source you trust!), and tell curl to use it. See http://curl.haxx.se/docs/sslcerts.html

    • For example, bitly has a simple API – here is an ugly implementation:

      longurl="http://example.com" #make sure it's url encoded
      bitly=`curl -s -A "$uagent" --get -d "login=LOGINNAME&apiKey=APIKEY&format=txt&longUrl=$longurl" "http://api.bitly.com/v3/shorten"`

  8. the same thing happens for me as well. it shows me logging in, getting the home page, posting and logging out. yet nothing is tweeted. double checked the login information and it is correct

      • Ubuntu 11.10

        I will be happy to provide any information I can give you to get this resolved. Just let me know.

        This is what I do but nothing is displayed on Twitter.

        bynw@outlaw:~$ bash tweet.sh “testing again”
        [+] Fetching twitter.com…
        [+] Submitting the login form…
        [+] Getting your twitter home page…
        [+] Posting a new tweet…
        [+] Logging out…

  9. My debug show this message :

    + initpage=’403 Forbidden (Rate Limit Exceeded)’
    ++ echo ’403 Forbidden (Rate Limit Exceeded)’

    Is it mean my ip is blocked?

  10. FYI: There is ONE bug – or at least a not so nice process: If you don’t enter anything as text, the script still does connect to twitter + does all the shenannigans.

    To avoid this, you simply have to add the following few lines right after the wordcount error handler:


    if [ "$tweet" == "" ]; then
    echo "[ERROR] Nothing to do / missing text."
    exit 1;
    fi

    cu, w0lf.

  11. Fun with the OS X Terminal – using Twitter

  12. Hello,
    Thank you for your Script. I’m new to Twitter Dev and I cant get any tweet on ma account. This is the cookie output. Is this normal? Thank you in advance!

    # Netscape HTTP Cookie File
    # http://curl.haxx.se/rfc/cookie_spec.html
    # This file was generated by libcurl! Edit at your own risk.

    .twitter.com TRUE / FALSE xxxxxxxxxxxx k xx.xx.xxx.xxx.xxxxxxxxxxxx
    mobile.twitter.com FALSE / FALSE 1 oauth_token
    mobile.twitter.com FALSE / FALSE xxxxxxxxxxxx _mobile_sess
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx–xxxxxxxxxx

  13. Is there a way to tweet the contents of a text file? Can’t figure out how to have the contents what comes after “bash tweet.sh “

  14. Been looking for an easy solution that doesn’t use OAuth for ages. This is a great solution. Thank you so much.

  15. recently updated to Ubuntu 12.04 LTS, CURL was updated to 7.22.0, my tweets doesnt post, no error messages tho… any ideas?

  16. I had problems with curl and SSL, so I had to put -k option to all curl calls.

    Also, on Solaris, commad tail should be “tail -1l ”

    But thanks for your script.

  17. Been using this script and its GREAT!
    Ran into some issues recently, I had a string that says “This is Alwyn & he is sexy!”, apparently twitter only displayed “This is Alwyn “.

    ‘&’ breaks the script… any ideas why its like this? should I type in ASII?

  18. Brilliant! Thank you very much for the script. This is my use case:

    I’ve set up a home git server. I want to use it when away from home but I’m not on a static IP. I’ve modified your script to DM from one twitter account to another. I just periodically poll for my external IP and DM myself the external IP address whenever it changes.

  19. Thank you so much! I set up a Twitter account for my home servers. I use your script to tweet system alerts from my servers to my personal Twitter account. I wrote a script to force updates of my DynDNS account every 25 days and I use your script to tweet the notification of the update.

  20. How can use this script to output the latest tweet to the command line and automatically update. ie tail username timeline count=1

  21. So, this is pretending to login on the website, rather than posting over API with oauth. I’m looking for a means to authentic with oauth and post with curl in bash. Does anybody have an example of that?

  22. This is so unbelievable, it really worked!!! I was looking all over for something similar and found none like this! KUDOS! I just had to add the -k switch to all curl commands to make it work. Thanks much.
    Jerome.

  23. I tried this script on ubuntu, and it works with no problem. However, I run it on a redhat machine.. and get the following error:

    [+] Fetching twitter.com…
    [+] Submitting the login form…
    [+] Getting compose tweet page…
    [+] Posting a new tweet: my tweet was here
    curl: no URL specified!
    curl: try ‘curl –help’ for more information
    line 40: https://mobile.twitter.com/: No such file or directory
    [+] Logging out…

    Any ideas?

    • Here you go! :) It uses the command line, just like the original. If you want to use it via browser, you’ll want to change $argv[1] to $_POST["tweet"] or whatever and add instead of the \n, or mute it altogether. Obviously it requires PHP with cURL enabled.

      #!/usr/bin/php
      <?php
      #Twitter status update bot by http://360percents.com
      #Author: Luka Pusic <pusic93@gmail.com>
      #Translated to PHP by Dawt Maytrikx
       
      #REQUIRED PARAMS
      $username = urlencode("username");
      $password = urlencode("password");
      if (isset($argv[1])) $tweet = urlencode($argv[1]); #must be less than 140 chars
      elseif (strlen($tweet) > 140) { echo "[FAIL] Tweet must not be longer than 140 chars!\n"; exit(1); }
      else { echo "[FAIL] Nothing to tweet. Enter your text as argument.\n"; exit(1); }
       
      #EXTRA OPTIONS
      $uagent = "Mozilla/5.0"; #user agent (fake a browser)
      $sleeptime = 0; #add pause between requests
       
      $host = fopen("cookie.txt", "w"); #create a temp. cookie file
      $ch = curl_init();
      curl_setopt_array($ch, array(//CURLOPT_MUTE => TRUE, //-s
                                   CURLOPT_COOKIE => "cookie.txt", //-b
                                   CURLOPT_COOKIEJAR => "cookie.txt", //-c
                                   CURLOPT_FOLLOWLOCATION => TRUE, //-L
                                   CURLOPT_SSLVERSION => 3, //--sslv3
                                   CURLOPT_USERAGENT => $uagent, //-A
                                   CURLOPT_RETURNTRANSFER => TRUE
                                   ));
       
      #GRAB LOGIN TOKENS
      echo "[+] Fetching twitter.com...\n";
      sleep($sleeptime);
       
      curl_setopt_array($ch, array(CURLOPT_URL => "https://mobile.twitter.com/session/new",
                                   ));
      $initpage = curl_exec($ch);
       
      preg_match("/<input.*authenticity_token.*value=\"(.*?)\".* \/>/i", $initpage, $matches);
      $token = $matches[1];
       
       
      #LOGIN
      echo "[+] Submitting the login form...\n";
      sleep($sleeptime);
       
      curl_setopt_array($ch, array(CURLOPT_URL => "https://mobile.twitter.com/session",
                                   CURLOPT_POSTFIELDS => "authenticity_token=$token&username=$username&password=$password",
                                   CURLOPT_POST => TRUE
                                   ));
      $loginpage = curl_exec($ch);
       
       
      #GRAB COMPOSE TWEET TOKENS
      echo "[+] Getting compose tweet page...\n";
      sleep($sleeptime);
       
      curl_setopt_array($ch, array(CURLOPT_URL => "https://mobile.twitter.com/compose/tweet",
                                   CURLOPT_POSTFIELDS => "",
                                   CURLOPT_POST => FALSE
                                   ));
      $composepage = curl_exec($ch);
       
      preg_match("/<input.*authenticity_token.*value=\"(.*?)\".*\/>/i", $composepage, $matches);
      $tweettoken = $matches[1];
       
       
      #TWEET
      echo "[+] Posting a new tweet: $tweet...\n";
      sleep($sleeptime);
       
      curl_setopt_array($ch, array(CURLOPT_URL => "https://mobile.twitter.com/",
                                   CURLOPT_POSTFIELDS => "authenticity_token=$tweettoken&tweet[text]=$tweet&tweet[display_coordinates]=false",
                                   CURLOPT_POST => TRUE
                                   ));
      $update = curl_exec($ch);
       
       
      #GRAB LOGOUT TOKENS
      curl_setopt_array($ch, array(CURLOPT_URL => "https://mobile.twitter.com/account",
                                   CURLOPT_POSTFIELDS => "",
                                   CURLOPT_POST => FALSE
                                   ));
      $logoutpage = curl_exec($ch);
       
      preg_match("/<input.*authenticity_token.*value=\"(.*?)\".* \/>/i", $logoutpage, $matches);
      $logouttoken = $matches[1];
       
      #LOGOUT
      echo "[+] Logging out...\n";
      sleep($sleeptime);
       
      curl_setopt_array($ch, array(CURLOPT_URL => "https://mobile.twitter.com/session/destroy",
                                   CURLOPT_POSTFIELDS => "authenticity_token=$logouttoken",
                                   CURLOPT_POST => TRUE
                                   ));
      $logout = curl_exec($ch);
       
       
      unlink("cookie.txt");
      curl_close($ch);
      exit(0);
      ?>
      

  24. Tweeting OpenBSD Network IP Changes With Minimal Dependencies | Adam Flott

  25. Technische Informationen 2012 (Archiv) | EarlyBird

  26. Technische Informationen 2012 | EarlyBird

  27. Hi,
    I have recommended your script here in the Netherlands.

    However, if I wanted to upload a picture, would that be hard to do?

    like this:
    bash tweet.sh “this is just beautiful” “./images/pic5″

  28. this should be doable with twitipic.com.

    For the API see below.
    Any coders around here willing to include this??

    http://dev.twitpic.com/docs/2/upload/

    curl -v -H ‘X-Auth-Service-Provider: https://api.twitter.com/1/account/verify_credentials.json‘ -H ‘X-Verify-Credentials-Authorization: OAuth realm=”http://api.twitter.com/”, oauth_consumer_key=”GDdmIQH6jhtmLUypg82g”, oauth_signature_method=”HMAC-SHA1″, oauth_token=”819797-Jxq8aYUDRmykzVKrgoLhXSq67TEa5ruc4GJC2rWimw”, oauth_timestamp=”1272325550″, oauth_nonce=”oElnnMTQIZvqvlfXM56aBLAf5noGD0AQR3Fmi7Q6Y”, oauth_version=”1.0″, oauth_signature=”U1obTfE7Rs9J1kafTGwufLJdspo%3D”‘ -F “key=098f6bcd4621d373cade4e832627b4f6″ -F “media=@/path/to/image” http://api.twitpic.com/2/upload.json

  29. I am currently working on a security script that snaps a picture using the webcam, I’m going to use your tweet script to post those pictures on my twitter page, or facebook page depending on which I choose, I will leave your name in the comments under the twitter and facebook script parts, I’ll post the finished security script on here if you like when I finish it, also looking into recording video and sound if password is typed incorrectly 3 times in a row.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>