Shell script bafflement

I recently downloaded a shell script that runs an embedded python script.
The first few lines looks like this:
<pre>
#!/bin/sh
exec python $0 ${1+"$@"}
</pre>
I know what #!/bin/sh does, and I know what "exec python" does, but what do the
<pre>
</pre>
and
<pre>
$0 ${1+"$@"}
</pre>
mean???
(The actual python script follows these lines.) I assume the gist of it is that it runs sh, captures any command line arguments given after the name of the shell script executable, and then turns this all over to python as if the python code that follows had been invoked from the command line with those arguments following.
But I'd like to understand it on the level of the actual syntax....

Daniel's post explains almost everything; I just want to add some minor points (and one question).
For /bin/sh, the first line
is equivalent to
which is do-nothing built-in command of sh.
(If the first line is
or
then sh will try to find a command "" and results in 'command not found'.)
Then the second line is executed by sh, and the process is replaced by python. The third line
is illegal (or incomplete) as a shell script, but it's not a problem because sh does not read the line.
Now python reads the script from the beginning again.
In python, """ starts a multi-line string. The string starts just after """, so the string is
:"<newline>exec python $0 ${1+"$@"}
This is not a comment for python, but python ignores any simple expression in a script anyway. For example
#!/usr/bin/python
a = "foo"
a
"bar"
is a legal python script. The second and third lines (a and "bar") are simple expressions and do nothing.
One of the reason for using this trick is portability. The main problem is that python may be installed in /usr/bin, /usr/local/bin, /sw/bin, or anywhere else, depending on the system. So if a python script starts with
#!/usr/bin/python
then it does not run if python is installed in other places. A trick often used is
#!/usr/bin/env python
which will search python in the user's PATH. But this trick works only if /usr/bin/env exists.
Now a (minor) question:
What is the difference between ${1+"$@"} and "$@"? The former is more portable than the latter? If so, why?
/bin/sh may be a pure (true) Bourne-shell, bash or ksh (or any other?) depending on the system. I tried both bash and ksh, but ${1+"$@"} and "$@" seem to give the same results.
PowerMac G4   Mac OS X (10.4.5)  

Similar Messages

  • Trying to create a shell script to cut/paste files in finder. Help needed.

    I'm trying to create an automator shell script to cut/paste. It'll function exactly like copy/paste. i.e. I'll just copy file/files with command+c like always, but then I'll create an automator which uses the "mv" terminal app to move the files which works exactly like cut paste.
    I need some help since I don't know the syntax for creating shell scripts.
    What I did so far is to do it in automator with Apple Script which goes like the following:
    on run {input, parameters}
    tell application "Finder"
    set theWindow to window 1
    set thePath to quoted form of (POSIX path of (target of theWindow as string))
    end tell
    tell application "Terminal"
    do script with command "mv \"" & input & "\"" & thePath in window 1
    end tell
    return input
    end run
    This gets the copied file path from clipboard before, as input, and then recognizes the active finder window as thePath so then executes the mv command for the input file to the thePath window.
    It doesn't work as expected since it connects both file/window paths into a single path instead of leaving a space between them so the mv command can't recognize two separate paths.
    What's the correct syntax for that line
    do script with command "mv \"" & input & "\"" & thePath in window 1
    to leave a space between input and thePath under the mv command?
    Also this requires the terminal app to be open in the background.
    After I get this to work I want to do the exact same thing using shell script within automator, so I won't need Terminal to be open all the time.
    And the next step will be to cut/paste multiple files/folders but that should be easy to do once I get the hang of it.

    Try using:
    on run {input, parameters}
    tell application "Finder"
    set theWindow to window 1
    set thePath to quoted form of (POSIX path of (target of theWindow as string))
    end tell
    do shell script "mv \"" & input & "\" " & thePath
    return input
    end run
    (45977)

  • How to call shell script from a pl/sql procedure

    Hi all,
    I am little bit new to plsql programming, i have a small problem as follows
    I have to call a shell script from a pl/sql procedure ..
    Please suggest me some methods in oracle 10g, which i could make use of to achieve my goal. also please tell me what are the constraints for those methods if any.
    I already came across dbms_scheduler, but i have got a problem and its nor executing properly its exiting giving 255 error or saying that permission problem, but i have already given full access to my shell scripts.
    Thanks in advance
    Best Regards
    Satya

    Hi,
    Read this thread, perhaps is there your response :
    Host...
    Nicolas.

  • Shell script in Applescript

    I have a program that I run via Terminal, but I don't want a terminal window open while I run it (Just personal preference). I have an applescript set up to run the Terminal command, but the thing is that the command is "on" while the program is running, Is there some way that I can have the command go and then end the script wihtout closing the program? Or am I out of luck and have to have the Terminal window open?
    The program I am using is located here http://sites.google.com/site/sc2gears/
    Thanks for the help!

    The program is distributed (according to the docs) as a .command file, so you can get the efect you want like so:
    do shell script "/Users/yourname/further/path/Sc2gears-os-x.command &> /dev/null &"
    the &> /dev/null tells applescript that you don't care about any output, so it moves on to the next command, and the closing & sets the process up as a standalone.  Note:
    If the process doesn't close itself automatically you'll need a separate way of doing that
    if the process produces output you want to keep, don't use /dev/null - use an appropriate file path
    (obviously) '/Users/yourname/further/path' needs to be replaced with the correct path to the command, and needs to be single-quoted/escaped if it contains spaces or other unix-confounding characters

  • How to retrive ip address of connected device in shell script or applescript

    Hi all,
    From Mac PC, how to get ip address of connected device in shell script or applescript.
    there is any way to launch an app on ipad in shell script or applescript.
    thank you in advance for your help
    Mickael

    Hi all,
    From Mac PC, how to get ip address of connected device in shell script or applescript.
    there is any way to launch an app on ipad in shell script or applescript.
    thank you in advance for your help
    Mickael

  • Running a shell script in a Cocoa-Applescript, from the Resources folder?

    Hello!
    I need to use a bash script, but the script must be IN the application. I placed them in the "Supporting files", but i am not able to find them using "do shell script"
    Thanks!

    If you stick the script in the Resources folder you can get it by
    path to resource "Bash Script"
    If you want to put it in the folder Supporting files you need to construct the path
    (path to me as string) & "Contents:Resources:Supporting files:Bash Script"
    (where Bash Script is the name of your script)
    Don;t know if there is a shorter way for the second case.

  • Do shell script problem in Applescript

    Hi,
    I am an Applescript novice and have been trying to write a code to go to a particular folder, look for all files in the folder tree with extension .m2v and run an executable file to decode them. My problem is that when I run my code (containing do shell script), it searches through all files and folders on Mac HD and starts decoding .m2v files elsewhere that I don't want.
    Eventually it runs out of space (.m2v file decoding takes a lot of space), because it is dumping all decoded .yuv files onto the HD.
    When I run the command on Terminal, it executes the decoding perfectly and stores the decoded files in the same folder.
    Please help me about what's going on.
    My code is something like:
    tell application "Finder"
    set DestinationFolder to "xxxxxx:xxxx:xxxx"
    set NumFolders to (get count of folders under Destination folder)
    repeat for SomeVar from 1 to NumFolders
    set FolderinQuestion to folder SomeVar of DestinationFolder
    -- Tried tell application "Terminal" here, but did not know --how to export the FolderinQuestion variable from Finder to --Terminal
    do shell script " \" cd \" & (POSIX path of (result as text));
    for file in `find $pwd \"*.mov\"`
    do
    /usr/local/bin/decode file
    done"
    end repeat
    end tell
    I would greatly appreciate some guidance.

    The root of the problem is that you're trying to quote the cd command for some reason:
    <pre class=command>do shell script " \" cd \" & (POSIX path of (result as text));
    ...</pre>
    In addition to that you're including the & (POSIX path of (result as text)) as part of the shell command whereas this should be OUTSIDE of the quotes in order to get evaluated
    If you work that through you'll end up with a shell command that looks like:
    <pre class=command>" cd " & (POSIX path of (result as text))</pre>
    If you try to run that in a terminal you'll get a cd : command not found error and that's why the rest of it appears to fail.
    The solution to that one is simple - just don't bother quoting the cd and put the POSIX path stuff outside of the quotes to get it evaluated at runtime:
    <pre class=command>do shell script "cd " & quoted form of POSIX path of (FolderInQuestion as text)) & ";
    # rest of shell commands here"</pre>
    Now, as for the rest of the script there are a few things I would change.
    First, unless you need to know the index, don't do:
    >repeat for SomeVar from 1 to NumFolders
    set FolderinQuestion to folder SomeVar of DestinationFolder
    the issue is that the number of folders to process may change during the script's execution (other processes may create or remove folders). This will, at best, cause some folders to be skipped and, at worst, cause the script to fail.
    If you're iterating through a list, the best option is to just:
    <pre class=command>repeat with FolderInQuestion in (folders of DestinationFolder)
    ...</pre>
    This automatically sets the iterator (in this case, FolderInQuestion, to the first item in the list and increments it for each iteration through the loop.
    Secondly, in your shell script itself, scrub the entire do/done loop. You're already using find, so have that do the hard work using the -exec switch:
    <pre class=command>find path -name "*.mov" -exec /usr/local/bin/decode {} \;</pre>
    In find's case, {} is substituted with the current file's path.
    Putting this together you'd get:
    <pre class=command>tell application "Finder"
    set DestinationFolder to "xxxxxx:xxxx:xxxx"
    repeat with folderInQuestion in (get folders of folder DestinationFolder)
    do shell script "cd " & quoted form of POSIX path of folderInQuestion & "; find . -name \"*.mov\" -exec /usr/bin/decode {} \\;"
    end repeat
    end tell</pre>
    Note that I've used 'quoted form of POSIX path' - this takes care of any shell-unsafe characters like spaces in the path name. I've also used \\; for the -exec switch - this is so that AppleScript passes the \ to the shell command rather than using it for its own escaping.
    But you're not done yet!
    There's still one fatal flaw in this process - and that is the fact that find by default, is recursive - it will walk through every directory that it finds.
    This means that if you start at the top folder and iterate through, find will find all .mov files and decode them. Your script then cd's to the first subdirectory and repeats the process - decoding all the .mov files in that directory and all its subdirectories even though they've ALREADY been decoded.
    The upshot is that you only need to run one loop starting at the top level. You don't need to iterate through all the subdirectories since find will do that for you.
    In addition to that, there might not be a need to use cd at all since the first argument to find is the directory to start searching in. Unless there's some reason that you need to start decode from the top level directory (e.g. is that where it saves the files?), you can drop the whole repeat loop altogether and just run with:
    <pre class=command>set startFolder to (choose folder)
    do shell script "find " & quoted form of posix path of startFolder & " -name \"*.mov\" -exec /usr/bin/decode {} \\;"</pre>
    That's the entire script - a radical compression of your original.

  • Problem with backtick replacing apostroph in applescript/shell script

    I've got a script that appears to be using a backtick instead of an apostrophe which is causing an error in my shell script. For the life of me I can't seem to find where the error is being generated?
    The script is attached below. I'm using Exiftool, an app that writes metadata to image files. The shell script
    set cmd to "exiftool -CopyrightNotice=" & exifCopyright & " " & thisFilePath & ""
    set theResult to do shell script cmd
    works fine but the following shell script
    set cmd to "exiftool" & space & authorStr & " " & thisFilePath & ""
    set theResult to do shell script cmd
    returns the error "sh: -c: line 0: unexpected EOF while looking for matching `''
    sh: -c: line 1: syntax error: unexpected end of file" number 2. The code in the event log in applescript editor looks exactly the same to me but one fails in the shell script.
    It has been suggested by the developer of Exiftool, Phil Harvey, that there is a backtick in the second shell script. I read somewhere in the applescript docs that this is due to a change in OS 10.6? Any suggestions on how to fix this?
    Thanks.
    Pedro

    Yea, the authorStr value has a space like "Joe Smith"
    Then you need to use quoted form of this string, too:
    set cmd to "exiftool " & quoted form of authorStr & space & thisFilePath
    although the format looks wrong to me - shouldn't there be some kind of switch, such as "-author=' before it?
    You have to consider how you'd enter this at the command line to work out how best to translate it to AppleScript. For example, if the command line version were:
    exiftool -author='John Doe' /path/to/some.jpg
    you can see the quotes are around the name, not the entire -author switch. In this case you should be looking at something like:
    set authorStr to "John Doe"
    set theFilePath to "/path/to/some.jpg"
    set theCmd to "exiftool -author=" & quoted form of authorStr & space & quoted form of theFilePath
    Now you could, of course, use quoted form when you create the variables (e.g. set authorStr to quoted form of "John Doe"), but that may screw you up later on if/when you try to use authorStr in some other way, so I find it best to use quoted form only where it's needed.

  • Shell Script or Applescript to run disk permissions repair

    Tried doing this Applescript in Automator:
    do shell script "sudo diskutil repairPermissions /" ¬
      password "yourAdminPassword" with administrator privileges
    This works, but the process appears to run without shutting down when it's done.
    Can anybody suggest an addition or modification to terminate when the permissions repair is completed?

    do shell script ¬
              "sudo diskutil repairPermissions / ; exit" password "yourpassword" with administrator privileges

  • Shell script friendly paths in applescript

    I have a python script that resides inside a standalone application bundle. I run this script from the app and call it by getting the path of the application bundle and adding '/Contents/Resources/' to the path. This script sets or gets information from a plist. So, adding a ' --list' to the script name returns the items of the plist.
    This is my applescript and RWplist is the python script.
    set plInfo to do shell script "/Users/[just me]/Desktop/Test Project/Test App.app/Contents/Resources/RWplist --list'
    This fails due the the spaces in the directory and app name. If I change the folder and app name like;
    set plInfo to do shell script "/Users/[just me]/Desktop/Test-Project/Test-App.app/Contents/Resources/RWplist --list'
    This works... I tried wrapping the path in single quotes, I tried to do a replace all spaces to '\\space' in the path... and adding the 'quoted form of POSIX path of'...
    I'm guessing I'm placing the single quotes or using the quoted form... improperly. Can someone please explain how to format a path in this manor. I can't seem to find the proper syntax for this.

    This fails due the the spaces in the directory and app name
    Right, this is a common problem that many people encounter.
    I'm guessing I'm placing the single quotes or using the quoted form... improperly. Can someone please explain how to format a path in this manor.
    quoted form is the preferred/recommended way of doing this. Here's an example:
    set cmdPath to "/Users/just me/Desktop/Test Project/Test App.app/Contents/Resources/RWplist"
    do shell script (quoted form of cmdPath) & " --list"
    If you want to build the script manually then you should single-quote the entire path, e.g.:
    do shell script " '/Users/just me/Desktop/Test Project/Test App.app/Contents/Resources/RWplist' --list"
    Note that there are single quotes around the command path but the --list parameter is outside of the single-quoted path.

  • Commands in shell script

    Hai all,
    I need to write a script to add in the cron
         a) exec a procedure
    if successful ,then
         b) Truncate one schema table in the DB
         c) exec a procedure
    Can anyone let me know how to do this ? if anyone have any pointers, for the same , please let me know
    DB : 11.
    Os: Solaris 5.10
    Kai

    Kai,
    Here are 3 function you can use in shell script for executing a statement, sqlfile and procedure
    function execStmt {
      typeset stmt=$4
      echo "
        set feedback off
        set verify off
        set heading off
        set pagesize 0
        whenever sqlerror exit 1
        whenever oserror exit 2
        $stmt;
        commit;
        exit 0
      " |  sqlplus -s  $1/$2@$3
      ret=$?
      if [ $ret -ne 0 ]
       then
          return 1;
       else
          return 0;
       fi
    function execSql {
      typeset sqlfile=$1
      if [ ! -f $sqlfile ]
      then
           echo
           echo "File containing extract count doesn't exist...." 
           echo "Exiting ..."
           echo
           exit 1;
      fi
      echo "
        set feedback off
        set verify off
        set heading off
        set pagesize 0
        whenever sqlerror exit 1
        whenever oserror exit 2
        @$sqlfile;
        exit 0
      " |  sqlplus -s  $2/$3@$4
      retcode=$?
      if [ $retcode -ne 0 ]
      then
           return 1;
      else
           return 0;
      fi
    function execPkg {
       echo "
       set feedback off
       set verify off
       set heading off
       set pagesize 0
       whenever sqlerror exit 1
       whenever oserror exit 2
       exec mypkg.procedure_name($4,$5); -- $4,$5 are argument list
        exit
      " |  sqlplus -s  $1/$2@$3
      ret=$?
      if [ $ret -ne 0 ]
      then
           return 1;
      else
           return 0;
      fi
    }Regards

  • Find & replace part of a string in Numbers using do shell script in AppleScript

    Hello,
    I would like to set a search-pattern with a wildcard in Applescript to find - for example - the pattern 'Table 1::$*$4' for use in a 'Search & Replace script'
    The dollar signs '$' seem to be a bit of problem (refers to fixed values in Numbers & to variables in Shell ...)
    Could anyone hand me a solution to this problem?
    The end-goal - for now - would be to change the reference to a row-number in a lot of cells (number '4' in the pattern above should finally be replaced by 5, 6, 7, ...)
    Thx.

    Hi,
    Here's how to do that:
    try
        tell application "Numbers" to tell front document to tell active sheet
            tell (first table whose selection range's class is range)
                set sr to selection range
                set f to text returned of (display dialog "Find this in selected cells in Numbers " default answer "" with title "Find-Replace Step 1" buttons {"Cancel", "Next"})
                if f = "" then return
                set r to text returned of (display dialog "Replace '" & f & "' with " default answer f with title "Find-Replace Step 2")
                set {f, r} to my escapeForSED(f, r) -- escape some chars, create back reference for sed
                set tc to count cells of sr
                tell sr to repeat with i from 1 to tc
                    tell (cell i) to try
                        set oVal to formula
                        if oVal is not missing value then set value to (my find_replace(oVal, f, r))
                    end try
                end repeat
            end tell
        end tell
    on error number n
        if n = -128 then return
        display dialog "Did you select cells?" buttons {"cancel"} with title "Oops!"
    end try
    on find_replace(t, f, r)
        do shell script "/usr/bin/sed 's~" & f & "~" & r & "~g' <<< " & (quoted form of t)
    end find_replace
    on escapeForSED(f, r)
        set tid to text item delimiters
        set text item delimiters to "*" -- the wildcard 
        set tc1 to count (text items of f)
        set tc2 to count (text items of r)
        set text item delimiters to tid
        if (tc1 - tc2) < 0 then
            display alert "The number of wildcard in the replacement string must be equal or less than the number of wildcard in the search string."
            error -128
        end if
        -- escape search string, and create back reference for each wildcard (the wildcard is a dot in sed) --> \\(.\\)
        set f to do shell script "/usr/bin/sed -e 's/[]~$.^|[]/\\\\&/g;s/\\*/\\\\(.\\\\)/g' <<<" & quoted form of f
        -- escape the replacement string, Perl replace wildcard by two backslash and an incremented integer, to get  the back reference --> \\1 \\2
        return {f, (do shell script "/usr/bin/sed -e 's/[]~$.^|[]/\\\\&/g' | /usr/bin/perl -pe '$n=1;s/\\*/\"\\\\\" . $n++/ge'<<<" & (quoted form of r))}
    end escapeForSED
    For what you want to do, you must have the wildcard in the same position in both string. --> find "Table 1::$*$3", replace "Table 1::$*$4"
    Important, you can use no wildcard in both (the search string and the replacement string) or you can use any wildcard in the search string with no wildcard in the replacement string).
    But, the number of wildcard in the replacement string must be equal or less than the number of wildcard in the search string.

  • Syntax for inserting a number in a shell script in applescript

    who can help me correct this code?
    the user will enter a number in a dialog box, and this variable will replace the 7 in the shell script.
    i cant seem to keep the syntax right, i keep erroring out.
    if days_back is "" then
    set dialog_1 to display dialog "please enter a number " default answer ""
    set the days_back to the text returned of dialog_1
    end if
    set the_result to (do shell script "mdfind -onlyin '/Volumes/Volume1' 'kMDItemFSContentChangeDate >=$time.today(-7)'")
    display dialog the_result

    Try using:
    if days_back is "" then
    set dialog_1 to display dialog "please enter a number " default answer ""
    set the days_back to the text returned of dialog_1
    end if
    do shell script ("mdfind -onlyin '/Volumes/Volume1' 'kMDItemFSContentChangeDate >=$time.today(-" & days_back & ")'")
    display dialog the result
    (54186)

  • I can't get a simple "do shell script" in AppleScript to work!

    Hi All,
    I can get simple commands like "do shell script "ls"" or "do shell script "ps"" to work in AppleScript, but I cannot get something like "do shell script "python -V"" to work. (yes, my shell script says: do shell script "python -V" (no double quotes!))
    This is driving me nuts!
    Can anyone help?
    - Jon

    python -V appears to direct its output to stderr. Try
    do shell script "python -V 2>&1"

  • How to do multiple shell scripts in AppleScript

    I got some solutions from previous posts on how to run sudo in Applescript, but there is still some minor syntax issues when I try to get to the destination directory. Usually in shell script I just type
    cd directory-destination
    in several lines to batch process those commands, but when I work with applescript, if I do do shell script for every "cd" command, instead of getting an overall result, I would get intermediate results individually.
    I read doc and learned that there might be a way to put commands together by using the & sign?
    Message was edited by: ttback

    An individual do shell script command runs in its own shell, so to perform multiple commands within that shell you need to combine them into a single statement. You can use the ampersand '&' operator to concatenate text strings, and the semicolon ';' to separate the commands, for example:set theFolder to "/Applications"
    do shell script "cd " & theFolder & "; ls -l ."See the technical note do shell script in AppleScript.

Maybe you are looking for