Slashdot Mirror


Adding Some Spice To *nix Shell Scripts

An anonymous reader writes "Developing GUI script-based applications is time-consuming and expensive. Most Unix-based scripts run in a CLI mode or over a secure ssh session. The Unix shells are quite sophisticated programming languages in their own right: they are easy to design and quick to build, but they are not user-friendly in the same way the Unix commands aren't (see the Unix haters books). Both Unix and bash provide features for writing user friendly scripts using various tools to build powerful, interactive, user-friendly scripts that run under the bash shell on Linux or Unix. What tools do you use that spice up your scripts on the Linux or Unix platforms?"

71 of 411 comments (clear)

  1. Pashua on OS X by iliketrash · · Score: 3, Informative

    On OS X, I use Pashua, http://www.bluem.net/en/mac/pashua/. This is a brilliantly simple thing to use. I also use it for other (non-script) languages for making a quick-and-dirty GUI that still looks nice and is a real Cocoa program.

    1. Re:Pashua on OS X by iliketrash · · Score: 3, Interesting

      If you would get your facts straight there would be no need to flame.

      OS X has been UNIX 03 (SuSv3) registered and POSIX compliant since 2007.

      FYI, no version of Linux is registered Unix.

      Read these and learn:
      http://en.wikipedia.org/wiki/UNIX_03
      http://images.apple.com/macosx/technology/docs/L416017A_UNIX_TB_FF.pdf
      http://www.apple.com/server/macosx/technology/unix.html

    2. Re:Pashua on OS X by iliketrash · · Score: 2, Interesting

      Oh, where to start. Comparing Aqua to Cocoa is like comparing bananas to cars. Aqua is the name for the GUI components http://en.wikipedia.org/wiki/Aqua_(user_interface) and Cocoa is the preferred API http://en.wikipedia.org/wiki/Cocoa_(API). Aqua has not been deprecated, not now and not "for years." You can write OS X apps in Aqua using Carbon which _has_ been deprecated for years but is still fully supported. Many popular (and older) OS X programs still run in Carbon such as Quicken, Igor Pro, and at least until recently, Microsoft Office.

    3. Re:Pashua on OS X by SolitaryMan · · Score: 2, Funny

      FYI, no version of Linux is registered Unix.

      Thank God for that!

      --
      May Peace Prevail On Earth
  2. None! by Anrego · · Score: 5, Insightful

    I know this is troll-ish, but the way I view it a script is just that.. a script. A series of commands to be executed in a specific order designed to automate a repetative task. Basic logic, control, and input are generally ok.. but interaction is in my opinion an indicator that your task is out of scope for a "script" and should become a full fledged application.

    (you may now freely argue amongst yourselves on the difference between a script and an application)

    There are a metric ass-tonne of dialog-type apps out there .. just google for your favorite toolkits prefix and "dialog" and you'll probably find something..

    gdialog
    kdialog
    xdialog
    etc..

    1. Re:None! by Antidamage · · Score: 2, Interesting

      Sometimes you just have too many flags to really want to be hammering things haphazardly into a single line. In that case guided scripts seem like a fine solution, too. Any simple frameworks out there to save reinventing the wheel?

    2. Re:None! by CAIMLAS · · Score: 2, Interesting

      Often, I find myself writing scripts dealing with tasks which are semi-automated: I need a couple variables of input to deal with variance, but for the most part it's a repetitive task.

      What you're referring to is a batch script; that's good and fine, and I need those two. But that doesn't mean that interaction delineates a "script" from an "application".

      Though, I agree on one thing: a script is a script. There's no need to throw a dialog on there unless it in some way cleans up your input/output code and/or makes parsing the input cleaner.

      --
      ~/ssh slashdot.org ssh: connect to host slashdot.org port 22: too many beers
    3. Re:None! by grcumb · · Score: 2, Interesting

      I know this is troll-ish, but the way I view it a script is just that.. a script. A series of commands to be executed in a specific order designed to automate a repetative task. Basic logic, control, and input are generally ok.. but interaction is in my opinion an indicator that your task is out of scope for a "script" and should become a full fledged application.

      Well, there's interaction and then there's interaction. The grey area between script and application might be larger than your instinct tells you....

      I do document processing for large volumes of legal materials. A number of my scheduled tasks require graduated responses. If the task completes as desired, then no interaction is necessary. If the task encounters one of a set of known issues, then some sort of logic is necessary to decide whether it needs a technical remedy or whether an expert legal editor needs to intervene.

      Because the steps are somewhat malleable (we receive documents from 20 different countries), it makes sense to break the process down into a series of discrete stages. Perfect for scripted solutions. But because interaction with humans might be required at any stage, we also need something a little more receptive to input than a number of command-line parameters.

      My scripts get wrapped into a proper framework that formalises the way in which they're run, their interfaces to syslog and email, as well as allowing custom logic (in the form of callbacks) in parsing STDOUT and STDERR. They're still scripts, but they run in an environment that smells a lot like userland[*].

      ----------------

      [*] Yeah, I know.

      --
      Crumb's Corollary: Never bring a knife to a bun fight.
    4. Re:None! by Anonymous Coward · · Score: 2, Insightful

      A series of commands to be executed in a specific order designed to automate a repetative task. Basic logic, control, and input are generally ok.. but interaction is in my opinion an indicator that your task is out of scope for a "script" and should become a full fledged application.

      So if your script needs to just ask for a path or a couple inputs to create a configuration file, should you build an installation utility? What if the script is just to ask for how many days of log files to keep? Should we install xdialog or zenity in order to put a nice GUI around "How many days of log files should be kept (1 or more, 0 to disable cleanup)?"

      It's this simplistic view of scripting that causes such idiocy as:

            #!/bin/sh
            LOGDIR=/mnt/fileserver/database_logs
            cd ${LOGDIR}
            rm -rf *

          (And yes, the above was a real script that I've seen)

      You're perhaps confusing a script with a batch file.

  3. Just Bash? by DarkKnightRadick · · Score: 2

    Limiting yourself much? Also *nix != bash and bash != *nix though I imagine all shells share a host of similar commands.

    --
    "There is a way that seems right to a man, but its end is the way of death." Proverbs 16:25 (NKJV)
  4. None, I have given up bash scripting by TheSunborn · · Score: 2, Interesting

    None, I have given up bash scripting. The syntax and semantic are simply to wierd. And it can't handle filenames with space in them without some serious hack magic.

    Maybe its time someone (re)-invent a total new shell, with a sane scripting language, commands with consistent names for the same arguments and in general something which don't feel like I live in 1980.

    And I am a fulltime linux used, and a software developer, and I do use the shell as an interactive interface, but I newer script it, and I always have the feeling that I am using a 20 year old interface with so many issues that its insane. Kinda like the same feeling I get when I use sas(The static package. Nice features HORRIBLE interface)

    1. Re:None, I have given up bash scripting by Anonymous Coward · · Score: 2, Funny

      it can't handle filenames with space in them without some serious hack magic.

      Use quotes

    2. Re:None, I have given up bash scripting by Anonymous Coward · · Score: 3, Funny

      That's what novice "experts" usually say to do. Then you end up getting filenames that contain quotes. So what started as just escaping spaces turns into escaping spaces and two types of quotes. Depending on the approach you use here, you may need to escape some other characters, just in order to escape quotes, just so you can escape spaces, just so you can deal with filenames containing spaces.

      Any sensible person would say "fuck it" and just use a real scripting language like Python, Ruby or Perl.

    3. Re:None, I have given up bash scripting by Hatta · · Score: 4, Informative

      Does `find . -print0 | xargs -0` really qualify as "serious hack magic"?

      --
      Give me Classic Slashdot or give me death!
    4. Re:None, I have given up bash scripting by ZeBam.com · · Score: 3, Funny

      Use Perl

    5. Re:None, I have given up bash scripting by Dadoo · · Score: 2, Insightful

      Use quotes

      Ummm... yeah. Try "tar tf file.tar | xargs rm", when some of the files in the archive contain spaces (or other shell special characters).

      --
      Sit, Ubuntu, sit. Good dog.
    6. Re:None, I have given up bash scripting by DaleGlass · · Score: 4, Informative

      Use:

      tar tf file.tar | xargs -d "\n" rm

      That will work unless the filenames contain newlines in them.

    7. Re:None, I have given up bash scripting by vux984 · · Score: 4, Insightful

      Simple solution: don't use filenames with spaces in them. They're an incredibly stupid idea. If you need something that looks like a space, use an underscore. The same practice has been done in C since the early 70s, since having spaces inside C tokens would be stupid.

      Simpler solution. Don't use computers.

      Seriously now. You expect all the end users out in the world to stop using spaces... just so your script works?

    8. Re:None, I have given up bash scripting by CAIMLAS · · Score: 4, Insightful

      You mean something like perl? Or maybe python?

      My vote is for perl. It's more common in a "base install" than any other shell (in the BSDs and most Linux distros) and has a non-trivial amount of power. It's good at dealing with path and input permutations and you can interface it with pretty much anything. Hell, pcre came from perl, and that's used almost everywhere these days: it's got a lot of things right for the little that's wrong, at least in terms of being a good scripting language.

      I avoid "shell" scripting (csh, sh, bash) if at all possible, too. The contortions necessary to do the frequently-necessary evaluations takes quite a bit longer, even with a chain of awk/sed/grep and the like. Unlike those languages, perl is entirely self-contained and does not have any system-specific oddities (eg. with a shell script, many system binaries are different and an option/parameter pair on one system might do something entirely different on another - or not work at all).

      I realize perl can often (usually) be difficult to read. But for my purposes, it's good enough, because I'm a bit of a prolific comment writer as a matter of process.

      --
      ~/ssh slashdot.org ssh: connect to host slashdot.org port 22: too many beers
    9. Re:None, I have given up bash scripting by Cougar+Town · · Score: 2, Insightful

      I expect competent programmers to not be lazy and properly escape/sanitize their inputs.

    10. Re:None, I have given up bash scripting by WeatherGod · · Score: 3, Funny

      Use Python

    11. Re:None, I have given up bash scripting by Ajaxamander · · Score: 2, Interesting

      From my understanding, the reason it's called "My Computer" in Windows is to force (lazy) programmers to handle spaces in file paths. But that could just be a rumor.

    12. Re:None, I have given up bash scripting by Darinbob · · Score: 2, Informative

      Because people want to use illogical syntax like "copy this file that directory" and have the shell figure out if this is referring to 4 different file names, or 3, or 2, or 1. Well actually they want to do slightly more sane things like "copy $file $dir" form a script, while expecting the shell to be smart enough to realize that the spaces in a command line are delimiters while at the same time the spaces in a variable's contents are not delimiters.

      Some command languages handle ok (ie, DCL, DOS) because they have each individual command parse its own command lines or expand variables. But sh expands all arguments before passing them to the commands; which is a logical and consistent way of processing arguments and there's nothing broken about it. Making all command uniform makes for easier shell scripting. Sure it means that sometimes you have to do extra work when you've got spaces in file names, but that isn't the fault of 'sh' but the fault of whoever shoved spaces in the file names in the first place.

      Like any programming language so far, you're always going to bump into "do what I mean not what I wrote" problems.

    13. Re:None, I have given up bash scripting by tzot · · Score: 2, Insightful

      So you've never reset IFS (or set it to a newline or tab) in your shell scripts? Your scripts just bail out instead of handling perfectly valid filenames? Because they are valid.
      You seem to transform the weakness of shell programs into an O/S guideline, and preach to that effect.

      --
      I speak England very best
    14. Re:None, I have given up bash scripting by Rudd-O · · Score: 2, Insightful

      Twenty years ago, the shell creators gave you the ability to enclose $VARIABLES in "$QUOTES". Methinks you BELIEVE you know how to script bash, but you have not really learned anything beyond typing commands in an interactive shell. Shell quoting is just so fundamentally obvious and they are mentioned so early in the bash manual, I have a REALLY HARD time believing you are a competent software developer (unless you program mirc scripts or in visual basic).

      --
      Rudd-O - http://rudd-o.com/
    15. Re:None, I have given up bash scripting by ae1294 · · Score: 2, Funny

      Use emacs. It's the best of all worlds...

    16. Re:None, I have given up bash scripting by camperdave · · Score: 5, Insightful

      You still need to work with the user's files, which will inevitably have spaces in them. If a space is a valid character in the filesystem then your scripts need to reflect that. Erroring out is not a valid solution.

      --
      When our name is on the back of your car, we're behind you all the way!
    17. Re:None, I have given up bash scripting by Blakey+Rat · · Score: 3, Insightful

      (try opening a DOS shell on XP and typing in a command using a filename with spaces, without quotes).

      Yah! Now try typing a command without using the letter 'R' or 'C'!!

      Oh wait, you're introducing a ridiculous handicap to demonstrate your retarded point. Turns out, here in the real world, keyboards actually *do* have a key for typing quotes-- so it doesn't fucking matter if the command requires quotes.

      Look, regardless of your "special" way of naming files, the point is that *other people* who don't share your retarded opinion are going to put spaces in the filenames sooner or later-- so you need to be able to cope with it!

    18. Re:None, I have given up bash scripting by vgaphil · · Score: 2, Informative

      You can manipulate the IFS variable if you are having problems with files with spaces.

      IFS=$'\n'

      for i in $(find /some/dir -type f)
      do
      echo $i
      done

      unset IFS

      --
      A clever person solves a problem. A wise person avoids it. -- Einstein
    19. Re:None, I have given up bash scripting by Just+Some+Guy · · Score: 2, Informative

      Use:

      tar -t --null -f file.tar | xargs -0 rm

      That will work unless the filenames contain nulls in them. They won't.

      --
      Dewey, what part of this looks like authorities should be involved?
    20. Re:None, I have given up bash scripting by Richy_T · · Score: 3, Insightful

      It doesn't have to be that way. I always try and write Perl to be readable rather than concise. Sure I might take 6 lines to do something that can be done in 1 and may use some other stuff that isn't particularly necessary but I'm writing to get the job done and for maintenance, not to show how clever I am.

  5. It's pricey but.... by Fluffeh · · Score: 2, Funny

    I always request the budget for a small unit of scantily clad maidens from management in addition to the team beer budget.

    One day.... one day....

    --
    Moved to http://soylentnews.org/. You are invited to join us too!
  6. Off the top of my head... by hkz · · Score: 4, Informative

    I work as a Linux netadmin and system developer, so I do a lot of shell programming in (ba)sh. Here's some of the niftier things you can do to a shell script:

    - Make colored output with shell escape sequences. Works especially well with red type for error messages, makes them really stand out.
    - Use inline functions a lot. The great thing about them is that you can pipe to them and use them in all kinds of places. For instance, to do mysql queries:

    mysql_query() { /usr/bin/mysql --user=root --pass=topsecret database
    }

    echo 'SELECT * FROM accounts' | mysql_query

    - "Here documents". For long MySQL sequences, something like the following (reusing the mysql_query function from above):

    cat - EOF | mysql_query
          SELECT bar
          FROM foo
          WHERE baz ...
    EOF

    This lets you easily format stdin for scripts and other programs. Also really useful for outputting HTML and stuff like that. Best thing is that variables are expanded inside the block.

    - The || and && operators. Check if a file exists, remove if so, else complain:
    [ -f /tmp/somefile.txt ] && rm /tmp/somefile.txt || echo "Does not exist!"

    Also common in this form:
    [ -x /usr/bin/necessaryprogram ] || { echo "aaargh"; exit 1; }

    - Making a "multithreaded" shellscript is also one of my favourites. Say, you want to start five virtual machines at the same time. Write a function that starts a vm, and call it a few times in a loop, backgrounding each instance with &, and saving their PIDs. Then have a "wait loop" that waits for the PIDs to exit the system (or for a timeout to occur).

    - Proper argument handling with getopt. Have your script take "real" arguments in any order, just like real binaries.

    This just scrapes the surface of the surface, of course. I learn new stuff every day.

  7. Since I live in my parent's basement... by the_humeister · · Score: 2, Funny

    I use the usual: sed, [, wget, etc to automate downloads of pr0n.

  8. I dissent by ZeBam.com · · Score: 2, Insightful

    I disagree with the premise that GUI interfaces are needed, desirable, or constitute "spicing up." Command line scripts are fine and dandy in my book.

    1. Re:I dissent by martin-boundary · · Score: 3, Insightful
      It's also plain short-sighted to program a script for a GUI.

      It implies that the script will only be run by human users (and probably, human users who happen to run a particular flavour of GUI). Traditional shell scripts are written for all users, not just human users.

      Why should developers care about non-human users? It's what makes automation possible. Every time time a script delegates work to another script, that's a non-human user scenario.

      If you build enough scripts that can be used by all users, then you have a critical mass and your system becomes really powerful. If you build enough scripts that can only be used by human users, then your system stays weak, for it is limited by the actions of a single human operator.

  9. Stop using the Shell by Bruce+Perens · · Score: 4, Interesting

    The shell is a poor clone of 1950's algol. Today, scripting in Ruby or Python yields scripts that can handle errors with advanced facilities like exceptions, and is more maintainable, and can connect to a number of different GUIs or the web.

    1. Re:Stop using the Shell by walkoff · · Score: 2, Interesting

      There are times when bash/ash/dash... are all that is available or can be made available. Ruby and Python and the myriad other scripting languages are all very good but in memory, cpu and diskspace starved devices shell is the way to go. even the mini-versions of perl and Ruby etc. are a PITA to get working in embedded devices especially if you are using uClibc.

    2. Re:Stop using the Shell by Bruce+Perens · · Score: 3, Interesting

      I like Larry and the rest of the crew, but I think we can confidently say that Ruby is an evolution from Perl. It used to be that CPAN was a big advantage, but ruby gems have come along pretty well since then. And there's a lot to be said for the Rails framework, even more in 3.0 .

    3. Re:Stop using the Shell by Bruce+Perens · · Score: 4, Interesting

      There are times when bash/ash/dash... are all that is available or can be made available

      Because you're running Busybox. Which means it's my fault :-)

      The evolutionary successor of busybox, which I've been thinking about for a while, will not use the shell language. We can raise the bar significantly.

    4. Re:Stop using the Shell by martin-boundary · · Score: 3, Interesting
      Sorry, those advanced facilities are overhyped. How do you (eg) pipe commands together in Ruby, Python or Perl?

      AFAIK(?), none of these languages come close to the simple expressivity of cmd1 | cmd2 | cmd3 > file1.

      The shell's purpose has always been to serve the user. From the perspective of a user, advanced programming facilities like exceptions are not just useless, but can seriously get in the way.

      Programmers write pages and pages of code, and they appreciate class hierarchies, vector operations, etc. Users write throwaway scripts that are run once or twice.

      Programmers like powerful languages that make maintenance easy. Users like powerful shells that make simple interactions really easy.

    5. Re:Stop using the Shell by Bruce+Perens · · Score: 2, Interesting

      One of the early shells - either Steve Bourne's or Ken Thompson's, was written in a set of macros that converted C into an Algol-like language. I was at the NYIT Computer Graphics lab running version 6 Unix on PDP-11, and the funny C was a headache to us systems programmers. Eventually that got cleaned up, later versions of the source probably don't include the macros.

      Working with servers??? I am really far from convinced Bourne shell has any advantage in expressiveness or functionality for that task. For example, even opening a file descriptor and then iterating upon it is awkward in Bourne shell - you end up stowing it as some FD number over 2, and then writing odd redirection like "3>&" on every line that connects with it.

    6. Re:Stop using the Shell by Bruce+Perens · · Score: 2, Informative
      This is actually the fault of the underlying operating system, not Python. The zombies are hanging around so that you can get their exit status. The problem is that this uses more than the few bytes necessary, and crowds up the process tables.

      I haven't looked at how Rails 1.9 garbage-collects a thread, but it doesn't look as if you have to join it to make it go away. 1.8 did not use OS threads, but just switched tasks when I/O blocked.

    7. Re:Stop using the Shell by Bruce+Perens · · Score: 3, Interesting

      none of these languages come close to the simple expressivity of cmd1 | cmd2 | cmd3 > file1.

      This is sort of like saying that no language has anything that lets you align text like FILLER PICTURE in old Fortran. Sure, but you don't need to do it. I don't ever have to pipe to sed, because I can do File("foo.txt").read.gsub(/^Foo.*Bar$/, 'Hello!') and get the same result.

    8. Re:Stop using the Shell by martin-boundary · · Score: 4, Insightful
      You're comparing end results, not interfaces.

      Sure you can get the same result, but the syntactic sugar in your example is much more verbose, and conceptually more complex.

      For each of the three components, there's a mental context switch (File object on the left, reader object in the middle, and substitution method on the right).

      The shell language does the right thing by handling components more uniformly (ie they all have STDIN/STDOUT regardless of the nature of the command). The user needs to know what each command will do, but he does not need to know if the result is an array object, or a stream ojbect, or a file object etc.

      The shell also has less redundancy. Compare cat foo.txt with File("foo.txt"), there should be no need for both parentheses and quotes. Now in the wider scheme of Ruby this redundancy makes perfect sense, but users don't need all this, only programmers do.

      Users need the bare minimum to communicate with the machine in a language that takes 30 seconds or less to type (or speak in a microphone...), but still lets them do as much as possible.

      It's an interface issue, it's got little to do with the range of things that can be done in the language. Ruby is much more powerful than bash, but bash is still better at starting and stopping programs (and rc is better than bash...).

    9. Re:Stop using the Shell by Bruce+Perens · · Score: 2, Informative

      It might be that Matz doesn't have the right hardware? Unfortunately running Electric Fence on the Ruby interpreter won't work for any significant program, too many allocations at one live page and one dead page per allocation, it fills up swap, thrashes the cache because all allocations are aligned, and thus it's too slow. But valgrind would probably work. If it still exists in the 1.9.2 snapshot it's worth doing that.

    10. Re:Stop using the Shell by SpaghettiPattern · · Score: 2, Insightful

      For example, even opening a file descriptor and then iterating upon it is awkward in Bourne shell - you end up stowing it as some FD number over 2, and then writing odd redirection like "3>&" on every line that connects with it.

      The problem is that in most half decent language you can express almost anything. It is about choosing to refrain from expressing. As I stated, to me shell scripting languages are mostly about setting up environments and starting shells.
      I've seen people creating monstrous programs in Bash -because apparently the f...ing could- using complex arrays, reinventing clib functions, resulting in an badly performing system, rendering their product unmanageable and thus becoming a liability.

      I program only since 3 decades and 2 of them professionally. I'm still looking for the fine equilibrium between what you could and what you should do. My focus in this era is on Java, Perl and Bourne shell. Java can do most things I need on application level on most platforms and is well accepted almost everywhere within the corporate world. Perl is suitable for slightly more complex system stuff, is readily available on most systems and skills are still around. Bourne shell I use for straight forward system stuff and is very available.

      I'd refrain from using Bash or Korn shells -not readily available, historically challenged-, from writing specific system programs in Java -no intrinsic POSIX support- and some other obvious permutations of language, applicability and practicality.

      A rather frivolous parallel would be to compare programmers and music composers. The best ones are mostly technically accomplished and excel at refraining from using phrases that would not fit the composition.

      Back to the Bourne shell. It is IMHO a truly remarkable piece of work, to be used for what it does best.

      --

      I hadn't the slightest objection to his spending his time planning massacres for the bourgeoisie... (P.G. Wodehouse)
  10. 3D goggles! by Anonymous Coward · · Score: 3, Funny

    Combined with red and blue text the goggles make my facepalm ASCII art really pop!

    You see, I use ASCII art in lieu of the dialog boxes for user feedback. It's more intuitive to show facepalm guy when I ask the user for a digit & they give me a letter. They understand right away that they're an idiot.

  11. Why by silas_moeckel · · Score: 4, Insightful

    The CLI is powerful because it's a CLI, you do not need or want pretty dialog boxes. Help is whats available with man --help usefull errors messages and the contents of /var/log. It works over 9600 baud serial and works pretty well so you can ssh from your smartphone with 1 bar and fix something at 3am before the GUI would have time to come up to a login screen. A good CLI expects things to be piped into and out of it and can get any required information via the command line. The power of the CLI is that you can chain bits together run to do things or wrap scripts around other scripts and do useful work.

    You point to a 20 year old book that mostly bitches about how slow/ugly X is, guess what things have come a long way, I run one laptop with native X and it looks good is responsive I export X all the time over ssh to my primary desktops. Take a step back and think why your trying to shoehorn GUI functions onto a CLI if you really need to do it look at some of the toolkits that can detect if there is a X server present and use that fallback to text gui and run entirely headless by pure command line but think long and hard about why you would want to do this.

    --
    No sir I dont like it.
  12. tools I found useful by tpwch · · Score: 5, Informative

    Here are some random things I find useful, related to user interaction (mostly becuase it notifies the user):

    Oven timer:
    sleep $((20*60)); xmessage "Dinner is done"

    Quick macro for automating some repetitive task in a program:
    xdotool type "something"; xdotool key Return; xdotool mousemove $x $y; xdotool click 1; (and so on)

    Copying a file to/from the clipboard (can also copy from /topipe, so the output of any command). Faster than opening a text editor:
    xclip -in file

    Notifying me when some specific thing changed on a website:
    CHECKLINE="$(curl -s http://somewebsite.org/somepage.html | grep "currently undergoing maintenence")"
    while true; do
        sleep 120
        [ -z "$CHECKLINE" ] && xmessage "somewebsite is open again" && exit
    done

    Or just checking for changes in general (I use this for notifying me when something changed when tracking something I ordered, so I know the minute the package is ready to get picked up at the post office):
    while true; do
        OLD_MD5=${MD5}
        CONTENT=$(elinks -dump 1 -dump-charset iso-8859-1 "http://someurl.com/track?id=someid")
        MD5=$(echo -n $CONTENT | md5sum -)

        [ "${MD5}" != "${OLD_MD5}" ] && {
            xmessage "$(printf "New action: :\n\n${CONTENT}")"
        }
        sleep 120
    done

    If you don't want to interrupt what you're doing with a pop-up you can pipe it to osd_cat instead to have the text appear over whatever program you're currently working with. Adding a few beep; beep; beep; beep; is also a good way to get your attention if you're not paying 100% attention to your computer all the time.

    --
    Posted by a Debian GNU/Linux user
  13. Best book for this -- hands down. by CFD339 · · Score: 4, Informative

    Linux Shell Scripting with Bash
    by Ken O. Burtch
    Sams Publishing

    One of only two "computer" books I've ever been able to just sit down and read rather than just using as reference (the other being Kathy Sierra's "Head First Java" -- which is amazing).

    Ken does a fantastic job at putting "just the right" level of background, detail, context, and and depth for someone new to shell scripting to get started, then to use the book as a reference for all the traditional tools (sed, awk, etc..).

    I've bought two copies, one for me and one I gave to someone else who wanted to learn how to do this stuff.

    --
    The problem with quotes on the internet, is that nobody bothers to check their veracity. -- Abraham Lincoln
    1. Re:Best book for this -- hands down. by actionbastard · · Score: 5, Informative

      The only bash scripting guide you will ever need:

      http://tldp.org/guides.html

      free as in beer.

      --
      Sig this!
  14. Visual Basic by Anonymous Coward · · Score: 2, Funny

    I know this is like cursing in the church, but I use VB for most tasks others would use shell scripts for. Why? For one, the syntax is more predictable. With Bash you always have to worry about special characters and I can't stand that. (Same reason I dislike Tex.) Secondly, if you need user interaction, it has a really easy to use GUI builder. When VB4 came out it was like 1995 or something. It is now 2010 and in my opinion, for building simple dialogues (or even not so simple ones) VB is still among the best. That said, it has downsides, the most important one is that piping is missing by default. However, there are Win32/Wine functions you can call to alleviate this. Put them in a standard module with some wrappers and it's like they're part of the language.

    1. Re:Visual Basic by siride · · Score: 2, Insightful

      Please, for the love of $DEITY, learn Perl or Python or Ruby or SOMETHING. VB's syntax is not predictable or reasonable if you've programmed with any other language or know how a computer works. And the other languages are actually cross-platform and can do everything VB can do and then some.

    2. Re:Visual Basic by siride · · Score: 2, Insightful

      You don't have to tell me. I'm fond of Perl. I do admit that it's easy to write obtuse code, but if you just try a little bit, you can write readable and straightforward code. In fact, some of the often-derided syntactic constructs make Perl easier to read, not harder.

  15. Re:Nice example. by hkz · · Score: 3, Informative

    Thanks, it's nothing I couldn't show a fella. Learnt a lot from my colleagues and from the O'Reilly 'Unix Power Tools' book. The Advanced Bash Shell-scripting Guide is pretty good (but chaotic) too.

    The syntax filter here munged some of the examples, though. The here document example will not work as-is, because there should be two 'less-than' signs in front of the minus sign. The mysql_query function probably also won't work (can't bother to run a test), because the newline after the first bracket mysteriously disappeared. So best to loop up the concepts in some kind of reference manual.

  16. tcl/tk by drolli · · Score: 2, Interesting

    Honestly it its just about adding a button so that its not necessary to remember the command line arguments/switches, i prefer tcl/tk. Lightweight, portable (and ported), and stable. And if you need a little more functionality, there are tons of libraries available.

  17. "Interaction" by betterunixthanunix · · Score: 4, Informative

    The way I look at it is this: the "interaction" may actually be with another script. The whole abstraction that Unix-like OSes enforce, at least with file based IO, is that it is irrelevant what is on the other side of a file descriptor -- a disk, a pipe, a user, a socket, or something else entirely.

    Of course, this all starts to break down with GUIs.

    --
    Palm trees and 8
  18. ksh by Fatal+Darkness · · Score: 2, Informative

    For Unix shell scripting purposes (and I know the Slashdot crowd may scoff at this but), nothing compares to KSH. It has many features not found in Bash and most other shells, such as coprocesses, associative arrays, compound variables, floating point arithmetic, discipline functions, etc. It's also fully extensible and posix compliant. For GUI scripts, almost all commercial Unixes include dtksh, which provides access to much of the Xt and Motif APIs. A TK version of ksh also exists.

    KSH just gets a bad rep because Unix vendors insist on only supplying an ancient version (ksh88), or its clone (pdksh) that lacks all of the functionality and behavior of the original. As a result most people have never used a modern version of the shell.

    Of there's a right tool for the right job. Depending on the nature of the task one might also want to consider perl, python, or some other scripting technology.

  19. Consistency is the only spice ... by bhepple · · Score: 5, Insightful

    As said previously, scripts are scripts and don't often need a GUI. But for grep's sake, make them consistent!!! The only spicing up _really_ needed are some standards:

    o output errors to STDERR; normal output to STDOUT
    o include (-h, --help) processing - and send it to STDOUT so the help can be piped to 'less'
    o use getopt(1) or process-getopt(1) so that options on the CLI parse in a predictable and standard way
    o keep it terse except for errors so that the user can easily see if it worked or not without scanning vast output
    o provide a --verbose option to help with tracking down those errors

    ... and the most annoying thing of all - make sure --help _always_ works, even if the script body itself can't - at least the user can then be told about what the prerequisites are.
    Head over to http://mywiki.wooledge.org/BashFAQ for much wisdom on how to write better bash scripts.

  20. Open source bash libraries by relinked · · Score: 2, Informative

    Here's a neat trick to access the output of commands as file handles:

    diff <( echo 'hello') <( echo 'world')

    Now that I've got your attention ;) I'll take this opportunity to plug my open source bash libraries:

    bash-script-lib, a collection of scripts that let you augment your own scripts with advanced capabilities:

    1. "script-input", which lets you create "cat"-like input handling that can accept both forms "my-script filename" and "cat filename | my-script".
    2. "script-targets", a framework for creating scripts that accept single or multiple "build-like" targets. You program just the targets; the framework takes care of the rest.
    3. "filesystem", a collection of functions for normalizing paths, checking the existence of directories, etc.
    4. "backups", a collection of functions for finding files, paths, and latest versions of files from amongst multiple tar files.
    5. "display", a collection of functions for tabulating output, converting end-of-line-delimited output into arrays, etc.

    bash-sys-manage, a collection of scripts that lets you manage VPS instances by installing components and backing up and restoring discrete aspects of a server. E.g.:

    install.sh system.apt system.locale system.users system.nginx nginx.config packages.utils.base packages.utils.build php.package php-fm.build apc.package memcache.package

    backup.sh system.users system.config mysql.database

  21. I only write trivial shell scripts by steveha · · Score: 3, Insightful

    I will quickly write a shell script any time I have some simple task I want to automate. You cannot beat the convenience:

    cd /some/directory/$1
    some_program --foo $2 --bar $3
    rm -f *.temp

    Wow, three lines, and it runs the program, then cleans up the temp files that program always litters in my directory. And I don't have to memorize the --foo and --bar options! Shell scripts rock!

    The problem comes when you start to do nontrivial things. When you start processing lists of files, and the files can contain spaces, the amount of quoting drives me insane. At that point I rewrite in Python.

    The spaces-in-file-names problem can bite even this trivial shell script! If any of the three arguments ($1, $2, $3) is specified as a string containing spaces, this script won't work, because the shell interpreter needs quotes at every step where it evaluates something. If you pass "my file.txt" as the second argument, the $2 won't evaluate to "my file.txt" in quotes, it just evaluates to the bare string. So to be fully safe, the above program needs to be:

    cd /some/directory/"$1"
    some_program --foo "$2" --bar "$3"
    rm -f *.temp

    And woe is you if you forget the quotes.

    Python loses in convenience for running a program... here's a Python equivalent of the above:

    import os
    import subprocess as sp
    import sys

    os.chdir("/some/directory/%s" % sys.argv[1])

    lst_args = ["some_program", "--foo", sys.argv[2], "--bar", sys.argv[3]]
    sp.check_call(lst_args)

    lst_args = ["rm", "-f", "*.temp"]
    sp.check_call(lst_args, shell=True) # run in a shell to get wildcard expansion

    At first glance this looks horrible. It's much more than the three terse lines of the original. But it's easier to get right, and this is safer to run. If the user specifies something silly for the first arg, or doesn't provide it, this program will immediately stop after trying to change directories. The original would change to "/some/directory" and blindly run on, trying to run "some_program" there, and who knows what would happen? Likewise, if "some_program" fails, this script will stop immediately, and the deleting of the *.temp files will not occur (making it easier to debug what's going on). Finally, in this code we don't have to worry about quoting the arguments; we can just use the arguments and it just works. It is much harder to write a fail-safe shell script: you would have to explicitly test that $1 is provided, and you would have to check the result of running "some_program" to see if it failed or not.

    The nontrivial scripts I write tend to have a lot of logic in the scripts themselves, and Python is much much more pleasant and effective for evaluating the logic. If I want to write a script that sweeps through a bunch of directories and deletes files that match certain criteria, it is so much easier to write the tests on the file in Python. If I write ten lines of "if" statements to look at a filename, that is ten lines where I didn't need to fuss with the double quotes. In Python, you can do things like
    junk_extension = (".temp", ".tmp", ".junk")
    if filename.endswith(junk_extension):
            os.remove(filename)

    Shell scripting cannot match this convenience. And note that if I use the native Python os.remove() I don't need to worry about quoting the filename; it can have spaces in it and os.remove() doesn't care.

    Other people might prefer to use Perl or Ruby. Either of those, or Python, are much better than shell scripts for anything nontrivial.

    steveha

    --
    lf(1): it's like ls(1) but sorts filenames by extension, tersely
    1. Re:I only write trivial shell scripts by OA · · Score: 3, Interesting

      I agree python is lots of fun... but I do not call following script to be nontrivial.

      > In Python, you can do things like
      > junk_extension = (".temp", ".tmp", ".junk")
      > if filename.endswith(junk_extension):
      > os.remove(filename)

      Your problem is: thinking ten lines of "if" statements to look at a filename.

      This kind of things are done in 1 liner single shell command. This is too simple to bother python.

      Please read about the "find" command. especially with --exec rm '{}' \;

      Osamu

    2. Re:I only write trivial shell scripts by steveha · · Score: 2, Insightful

      I do not call following script to be nontrivial.

      I don't think I said it was nontrivial; I just said that Python was more convenient. If you wanted to test a single file and see whether it ended with one of three extensions in a shell script, what would you do?

      You could do it this way, but it's painful and ugly:

      # shell variable "filename" holds the filename
      if [ "${filename#*.}" = "temp" ] || [ "${filename#*.}" = "tmp" ] || [ "${filename#*.}" = "junk" ]; then
              echo "$filename"
      fi

      Don't forget to put spaces around the square brackets, or you get errors.

      Really, how would you solve this problem in shell? If you have a slick solution I'd love to learn it.

      Your problem is: thinking ten lines of "if" statements to look at a filename.

      Wow! It was so very kind of you to figure out my problem and inform me. Thanks!

      Please read about the "find" command. especially with --exec rm '{}' \;

      Oh, everyone's favorite user-friendly command, find(1). What an amazingly baroque set of command-line arguments it takes!

      I trust you realize that using find(1) to delete a single file is about like using a chainsaw to cut butter to put on a piece of toast.

      But if you want to remove all files that end with *.temp, *.tmp, or *.junk from a whole set of directories, it's this simple and friendly command:

      find /path/to/top/directory \( -regex ".*\.temp" -o -regex ".*\.tmp" -o -regex ".*\.junk" \) -exec rm {} \;

      Don't forget that you have to put a backslash before the parentheses or the shell complains. Don't forget to put a space between your escaped parentheses and the find(1) predicates. Don't forget to use those parentheses or else the -exec command will bind with the last predicate (in this example, it would only delete the *.junk files).

      Or, if you know your target platform is using GNU find(1), you can shorten it a lot:

      find /path/to/top/directory -regextype awk -regex ".*\.(temp|tmp|junk)" -exec rm {} \;

      That assumes that you already knew that in AWK it is legal to put regular expression alternatives in parentheses, separated by vertical bars. Of course, you can also do this trick without specifying AWK mode but you need to backslash escape the parens and the vertical bars in the regexp that specifies the alternatives:

      find /path/to/top/directory -regex ".*\.\(temp\|tmp\|junk\)" -exec rm {} \;

      You can do crazy powerful things with find(1) but it's syntax is annoying. I'd rather write a simple Python script using os.walk, such as:

      import os
      import sys

      junk_extensions = (".temp", ".tmp", ".junk")

      for dirpath, dirnames, filenames in os.walk(sys.argv[1]):
              for basename in filenames:
                      fname = os.path.join(dirpath, basename)
                      if fname.endswith(junk_extensions):
                              os.remove(fname)

      And really, if I'm doing this a lot, I'll write a simple Python function that hides some of the ugly details. And again, the Python solution is more bulletproof; it doesn't matter if any filenames have spaces in them, you get a sensible error message if you forget to specify an argument, etc. find(1) scares me; its syntax is tricky, and you are doing things over whole directory trees. If I'm going to automatically delete a bunch of files, I kind of want them to be the correct ones, and the Python is much easier to get correct.

      Okay, I wrote lots of code. Your turn. Please show us all your most elegant solution, in shell script, to the problem of identifying whether a file has any extension from (".temp", ".tmp", ".junk).

      steveha

      --
      lf(1): it's like ls(1) but sorts filenames by extension, tersely
    3. Re:I only write trivial shell scripts by Anonymous Coward · · Score: 2, Informative

      Your problem is: thinking find for simple cases :)

      rm -f *.{temp,tmp,junk}

  22. And use Python or Ruby instead? Not so easy by bzipitidoo · · Score: 3, Insightful

    I use sh and relatives (and vi) because they're ubiquitous, stable, small, light, and reasonably fast, consistent, capable, and fairly understandable. Every program in /etc is a shell script, and by default system utilities such as cron call on sh. Everything entered at a command line is interpreted by sh. sh is as much a part of UNIX systems as C. You might as well suggest GNU/Linux be rewritten in a better language than C.

    And if you're going to suggest that, why not also reexamine the basic architecture of UNIX? If anyone produces an open, formally verified microkernel OS in Haskell that actually works, isn't dog slow, and has sufficient functionality and apps to be useful, I'll surely check it out. I'd love to see more consistency between how applications accept parameters from the command line and how programming languages handle parameters. The former tends to be named and unordered, while the latter is anonymous and ordered. Then there's the defacto standard for libraries, worked out in the days when memory and disk space was extremely limited. It doesn't support enough meta information, making it necessary for a compiler to read header files. It's made libraries many little worlds of their own. As long as a programmer sticks to C/C++, it is relatively easy to call C library functions, but step outside that and it becomes a huge pain. Therefore we have these monstrous collections of duplicate functionality and wrapper code such as CPAN, abominations such as SWIG, attempts to bridge things by providing some commonality and standardization such as CORBA, and separate worlds such as the gigantic collection of Java libraries.

    Something like Perl or Java is heavy enough to be impractical on a slow computer with little RAM. Can take over 5 seconds just to load the language. I'm not familiar enough with Python or Ruby to know if they're as heavy. You can't always be sure they're there, whereas whatever was used in /etc/rc.d, and is run in a terminal, is guaranteed to be present. Don't know about a "pysh", but there is a "perlsh", for use in a terminal. Never seen perlsh used though, and it seems to demand a nasty hackish sort of interaction. Press Enter twice to execute commands, as one press of Enter is apparently used as a statement or formatting break. Maybe that's because those languages actually aren't too suitable for an interactive environment? As to connecting to the web, there's wget, wput, and curl.

    It could be a lot worse. Bash is pretty nice compared to MS DOS batch language.

    --
    Intellectual Property is a monopolistic, selfish, and defective concept. It is "tyranny over the mind of man"
  23. Re:Handling spaces by Qzukk · · Score: 2, Informative

    something like "for file in *" in bash will ignore special characters and run the loop once, for each actual file.

    bash's for loop understands * as a special case. if you need something like "for file in $(find ...);" you'll get one loop per word again. Also, even when you get one loop per file, you still have to quote $file when you use it because bash parses arguments to the command after variable substitution, so something like touch $file when $file is foo bar becomes touch foo bar where foo and bar are separate arguments, rather than what most people would expect (that the value of $file would be passed to the command as a single argument)

    Removing space from $IFS (the "standard" way is to make it tab and newline: IFS=$(echo -en "\n\b") ) fixes many of these quirks.

    --
    If I have been able to see further than others, it is because I bought a pair of binoculars.
  24. Rules of shell scripting by Leolo · · Score: 2

    The first rule of shell scripts is "you don't write programs in shell."
    The second rule of shell scripts is "you DON'T WRITE PROGRAMS IN SHELL." Seriously. You want perl or some other high level language.
    The third rule is to start your script with "#!/bin/bash", not /bin/sh. Your script probably contains bashisms and you don't even know it. What's more, bash has some great features that are only available if you use it explicitly in your shebang.
    The fourth rule would be to read the bash faq at http://mywiki.wooledge.org/BashFAQ as it contains many tips and tricks that won't be obvious just by reading the man pages.

  25. Well... by Anonymous Coward · · Score: 3, Funny

    I would, don't get me wrong. Emacs is a lovely operating system. I just wish it had a decent text editor.

  26. Blur! by flajann · · Score: 2, Interesting
    The line between what is a "script" and what is an "application" has been blurred. Ruby, Python, and PHP are all "scripting languages" and yet many, many killer applications are written in them (like Blender, for example!).

    Bash scripting definitely has everything you'd need to write an "application" in, but many data constructs would be awkward to implement in Bash, so you'd use Python, Perl, or Ruby.

    But what I can do in Bash I could also do in Ruby or Python very easily. What I could do in Ruby or Python would be very difficult to do in Bash.

    Then you have Java and C++ which are clearly not scripting languages, but I could do everything there that I could do in Bash. On the other hand, most things interesting you can do with C++ would be next to impossible with Bash. You just can't beat the performance of compiled languages. On the other hand, development would be costlier and portability might be an issue.

    Then again, you can tap a thumb tack in with a sledge hammer, but you run the risk of putting a nasty hole in your wall!

    It all comes down to what is the right tool for the job. So many tools, though! So pick and choose wisely. But you knew that already.

    Personally, I have given up on making a distinction between what is a "scripting language" and what's an application language. Javascript(!) is a "scripting language", but there is a high level of interactivity in the applications it's used for typically. Both in communicating with the server (AJAX) and with the user.

    Many of these so-called "scripting languages" allows for object-oriented programming. Bash, of course, does not. But then it was never meant for that level of sophistication. But that's even more blur for you. But you knew that already too.

  27. Re:Are you serious? by Bruce+Perens · · Score: 2, Interesting

    I have written some pretty sophisticated shell programs, including one thing for Debian that took a set of executables and a set of shared libraries and made versions of the libraries containing only the functions called for in the executables. It got the system to fit on a floppy when it otherwise would not have. It did a lot of list-processing in shell. Fortunately, someone eventually replaced that with a non-sh program.

    At this point I would not write another large shell script of any kind, and am mostly doing the three-liners in Ruby as well.

    The reason you would learn the shell would be to pass a certification test. You would be a better sysadmin or programmer if your main scripting language was Python or Ruby.