I have a bash script that contains a small amount of Apple Script as well. This script is for printer management. We have some MFD printers that require mapping by IP at our organization, and then for all other printers we use a print server/queue name.
If the script only includes a single conditional, mapping these MFD's with the method we're using works perfectly. For example:
INPUT=/Users/Shared/File.csv
OLDIFS=$IFS
IFS=","
while read Asset PQN IP Model Manu
do
if [ "$Manu" == "Canon" ]; then
$tagnum = $Asset
sudo mv -n /Users/Shared/Drivers/* /Library/Printers/PPDs/Contents/Resources
sudo mv -n /Users/Shared/Canon /Library/Printers/
lpadmin -E -p "$PQN" -v "lpd://$IP" -P "/Users/Shared/PPD/$Asset.ppd" -o printer-is-shared=false
cupsenable "$PQN"
cupsaccept "$PQN"
if [ $? -eq 0 ]; then
osascript -e 'tell app "System Events" to display dialog "Printer '$PQN' Added!"'
else
osascript -e 'tell app "System Events" to display dialog "Error on Manu - The printer '$Asset' could not map correctly. Please call X at x." with text buttons {"OK"}'
fi
else
do stuff here
fi
done < $INPUT
If I were to remove the else statement here and just use the single if statement, it works no problem. However, if I add the else statement, it always, without fail goes to whatever the else statement is. This holds true if I turn it into an if, elif, else statement as well. I change the conditional not at all, but if it's anything but a solitary conditional statement then it always ignores the statement (even though it's true) and goes to the else or last argument.
Is it something to do with being in the while loop? I can't wrap my head around the logic. Ideally once we figure out how to make it so it doesn't always go to the last conditional option, we can add another argument so that we can map the non-MFD printers using print server/queue name, which we have working fine as well in another script. Currently that's not possible as I can't figure out how to do more than one argument without this issue occurring.
Related
I tried to answer another SO question with a simple menu using the builtin select statement. The code displays names from /etc/passwd, and let you select a name by giving a number:
PS3="Enter a number: "
select name in $(cut -d: -f1 /etc/passwd) ; do
if [ -n "${name}" ]; then
break
fi
echo "Sorry, please enter a number as shown."
done
echo "Entry from passwd is: ${name}"
The works fine except for the very first time. When you give a correct answer the first time it will ask you to try again.
I tried to get a more detailed explanation of the first time, but I couldn't get a reproducable cook-book. When you copy-paste this code on your server, and give a correct answer you will probably have the same problem. When you repeat the command (from history or a new paste), the code shows now problem. I tried to get the problem again by logging out and logging in (sometimes it works) or rebooting.
I tried different ways to reproduce the problem in other situations (using different variable names, unsetting variables, using a slow list of values with select name in $(echo One; sleep 1; echo Two; sleep 2; echo Three; sleep 1); and opening a new shell.
I searched for other examples with select, but I can't find clues in other posts like https://stackoverflow.com/a/16750755/3220113 and https://askubuntu.com/a/1716.
I tried to fix my code with a sync and that seems to be a work-around:
PS3="Enter a number: "
select name in $(cut -d: -f1 /etc/passwd) ; do
# is sync needed here?
sync
if [ -n "${name}" ]; then
break
fi
echo "Sorry, please enter a number as shown."
done
echo "Entry from passwd is: ${name}"
I couldn't reproduce the error when I include the sync command. Is sync really a working patch and why do I need this here?
I do not need other ways to write a menu. I already found the graphical dialog Dialog from bash script and was looking for a simple replacement of my own over-complicated https://unix.stackexchange.com/a/115371/57293.
This problem only occurs when you type the commands interactively, not in a script. The reason is that the line you type after the select line is being used as the response to the prompt. Since if isn't in the menu, it reports an error. Then it doesn't execute the if command, because it was read as the response to the prompt.
It's not a problem in a script because the commands in the script are not used as standard input.
Hi I'm trying to write a simple bash script to attach to a screen session. If the session is not already started then it will start it and try to attach again.
The problem I'm having is with the if statement; it should compare the output from the screen command with the failure message and if they are equal go on to start the session and attach. But it's always going to the else clause, printing out the error message I was checking against :s
Both strings contain the same thing:
"There is no screen to be attached matching sctest."
but bash thinks they are different...
Here's the bash script, what am I missing?
#!/bin/bash
screenOutput=$(screen -aA -x sctest);
failString="There is no screen to be attached matching sctest.";
if [ "$screenOutput" = "$failString" ]; then
echo "screen session not started. starting now...";
# . ./init.sh
# echo $(screen -aA -x sctest);
else
echo "$screenOutput";
fi
Use set -x (or invoke bash -x yourscript) to print each line as it's evaluated with values expanded in a way that makes hidden characters visible and human-readable.
Most likely, you'll see something like the following:
[ 'There is no screen to be attached matching sctest' = $'There is no screen to be attached matching sctest\r' ]
...with the latter having a \r on the end. This is a carriage-return.
To remove it, you can modify your code like so:
screenOutput=$(screen -aA -x sctest)
screenOutput=${screenOutput%$'\r'}
I'm on macOS. I have a script that, after asking for confirmation using read in Terminal, uses grep to check whether /dev/disk1 is mounted, then formats that disk. That's a dangerous script, hence why asking if it's okay first is vital.
Eventually, I would like to have this script be an executable that the user can double-click on. But rather than having the user type "y" and Return into a Terminal window, I would rather a display dialog appear with "yes" and "no" buttons, have them choose, then have the script run based on their answer. Is this possible in bash?
I'm working in an environment in which I don't have administrative access, so while I can write an AppleScript Service to accomplish what I want to do and to integrate this elegantly into the user interface, I can't integrate that Service into the environment without the admin password (since I can't edit ~/Library/Services for the user without it). Also, I cannot download or install any new libraries, applications — anything, really — in the environment; I must only use native bash in Mac OS X.
Here is what I have:
read -p "Are you sure you want to partition this disk? " -n 1 -r # Can I make this be a dialog box instead?
echo
if [[ $REPLY =~ ^[Yy]$ ]] # Can this accept the result as a condition?
then
if grep -q 'disk1' /dev/ && grep -q 'file.bin' ~/Downloads; then
echo # redacted actual code
else
osascript -e 'tell app "System Events" to display dialog "The disk is not mounted."'
exit 1
fi
else
exit 1
fi
Thanks very much for your help.
Yes, it is possible in bash to take the output of an osascript dialog. Here’s an example with a Yes/No dialog box:
#!/bin/bash
SURETY="$(osascript -e 'display dialog "Are you sure you want to partition this disk?" buttons {"Yes", "No"} default button "No"')"
if [ "$SURETY" = "button returned:Yes" ]; then
echo "Yes, continue with partition."
else
echo "No, cancel partition."
fi
If you run this script, the script should echo the appropriate line depending on which button was pressed.
It also shows how to set the default button, which I am assuming for the example is “No”.
If you have a more complex dialog, you would most likely use a regex to detect the responses, as you do in your own sample; though depending on your use case you might want to guard against spoofing responses.
If you're happy with a text-mode (but cross-platform and proven) solution, try using ncurses, and in particular a utility called dialog.
dialog --yesno "Are you sure you want to partition this disk?" 5 50
answer=$? # Returns: 0 == yes, 1 == no
More details in this tutorial.
I don't have much experience with shell scripting and don't fully understand passing arguments to if else statements. I want to check the state of an auto proxy, i.e. whether it is enabled or disabled. if it is enabled(has an url) i want to turn it off and vice versa.
so far i have:
#!/bin/bash
if [[networksetup -getautoproxyurl "Wi-Fi"] = "https://mediahint.com/default.pac"] then
networksetup -setautoproxystate "Wi-Fi" off
osascript -e 'tell application "Terminal" to quit'
else
networksetup -setautoproxyurl "Wi-Fi" https://mediahint.com/default.pac
osascript -e 'tell application "Terminal" to quit'
fi
it's just the argument of the if statement i'm not sure on.
the statements work fine i have checked in another script.
Syntactically, all is ok, except the fiest line.
You must write:
if [ `networksetup -getautoproxyurl "Wi-Fi"` = "https://mediahint.com/default.pac" ]; then
Note:
backticks ``, that mean command subsitution;
; before then;
space before ] and after [.
Google suggests
echo "input" | osascript filename.scpt
with filename.scpt
set stdin to do shell script "cat"
display dialog stdin
However, I could get only blank dialog: it has no text. How can I get stdin from AppleScript at the version?
My OS version is OSX 10.8 Mountain Lion.
Sorry, not enough reputation to comment on answers, but I think there's something important worth pointing out here...
The solution in #regulus6633's answer is not the same as piping data into osascript. It's simply stuffing the entire pipe contents (in this case, echo output) into a variable and passing that to osascript as a commandline argument.
This solution may not work as expected depending on what's in your pipe (maybe your shell also plays a part?)... for example, if there are null (\0) characters in there:
$ var=$(echo -en 'ABC\0DEF')
Now you might think var contains the strings "ABC" and "DEF" delimited by a null character, but it doesn't. The null character is gone:
$ echo -n "$var" | wc -c
6
However, using #phs's answer (a true pipe), you get your zero:
$ echo -en 'ABC\0DEF' | osascript 3<&0 <<EOF
> on run argv
> return length of (do shell script "cat 0<&3")
> end run
>EOF
7
But that's just using zeros. Try passing some random binary data into osascript as a commandline argument:
$ var=$(head -c8 /dev/random)
$ osascript - "$var" <<EOF
> on run argv
> return length of (item 1 of argv)
> end run
>EOF
execution error: Can’t make some data into the expected type. (-1700)
Once again, #phs's answer will handle this fine:
$ head -c8 /dev/random | osascript 3<&0 <<EOF
> on run argv
> return length of (do shell script "cat 0<&3")
> end run
>EOF
8
According to this thread, as of 10.8 AppleScript now aggressively closes standard in. By sliding it out of the way to an unused file descriptor, it can be saved. Here's an example of doing that in bash.
Here we get at it again with a cat subprocess reading from the magic fd.
echo world | osascript 3<&0 <<'APPLESCRIPT'
on run argv
set stdin to do shell script "cat 0<&3"
return "hello, " & stdin
end run
APPLESCRIPT
Will give you:
hello, world
I know that "set stdin to do shell script "cat"" used to work. I can't get it to work in 10.8 though and I'm not sure when it stopped working. Anyway, you basically need to get the echo command output into a variable which can then be used as an argument in the osascript command. Your applescript needs to handle arguments too (on run argv). And finally, when you use osascript you must tell an application to "display dialog" otherwise it will error.
So with all that said here's a simple applescript which handles arguments. Make this the code of filename.scpt.
on run argv
repeat with i from 1 to count of argv
tell application "Finder"
activate
display dialog (item i of argv)
end tell
end repeat
end run
Here's the shell command to run...
var=$(echo "sending some text to an applescript"); osascript ~/Desktop/filename.scpt "$var"
I hope that helps. Good luck.
Late to this, but the original AppleScript seems to try to do something not allowed with osascript.
If in the original filename.scpt this line:
display dialog stdin
Is changed to:
tell application "System Events" to display dialog stdin
Then passing a value via stdin (as opposed to command line arguments) definitely still works in 10.7.5 Lion, maybe 10.8 Mountain Lion too.