I am by no means an AppleScript expert, but get by. I am running into a hell of a time trying to pass some AppleScript variables to a sed command in order to replace some text in a file, based on the variables.
I have two dialog boxes in AppleScript that grab user data, and I store those variables. myData - This works OK.
set myData to text returned of ¬
(display dialog "Enter Your Data" with title ¬
"Data Entry" default answer ¬
"" buttons {"Continue…"} ¬
default button 1 ¬
)
set searchFor to quoted form of "data1"
set searchFor2 to quoted form of "data2"
set inputFile to "/Users/User1/Desktop/file.txt"
set outputFile to "/Users/User1/Desktop/file1.txt"
do shell script quoted form of ("sed -i.bak s/" & searchFor & "/" & myData & "/g") & " " & inputFile & " > " & outputFile
I actually get this error: No such file or directory, exit code 127. The weird part is, though, that it does write out the file with zero data in it. I am not necessarily trying to write out a diff file as the script suggests, just edit data in place. However, I've had zero success that way, which is why I approached it this way.
Any assistance with my issue would be greatly appreciated!
Your immediate issues are that you mistakenly apply quoted form of multiple times, and, more to the point, apply quoted form of to the sed executable name, its options, and the sed script together, which invariably breaks (see below for a detailed explanation); try the following - without applying quoted form of to any of the variables beforehand - note how quoted form of is applied selectively to the sed script and the in- and output files, respectively:
do shell script "sed " & quoted form of ¬
("s/" & searchFor & "/" & myData & "/g") ¬
& " " & quoted form of inputFile & " > " & quoted form of outputFile
Note that I've removed -i.bak from your command, because it would invariably result in an empty output file: -i updates the input file in place, producing no stdout output. Thus, nothing would be sent to outputFile with > outputFile.
However, this can still break or misbehave, if searchFor and myData contain either / or characters that have special meaning in a sed regular expression (e.g., \, *, [, ...) or replacement string (e.g., &, \).
To avoid that, you'll have to escape the input strings first, which is non-trivial, unfortunately.
The following handlers provide robust, generic escaping - they are based on this answer, where the underlying commands are explained[1]) :
# Quotes (escapes) a string for safe use in a `sed` regex.
on quoteRegex(txt)
do shell script "sed -e 's/[^^]/[&]/g; s/\\^/\\\\^/g; $!a\\'$'\\n''\\\\n' <<<" & quoted form of txt & " | tr -d '\\n'"
end quoteRegex
# Quotes (escapes) a string for safe use in a `sed` substitution string (`s///` function).
on quoteSubst(txt)
do shell script "IFS= read -d '' -r <<<\"$(sed -e ':a' -e '$!{N;ba' -e '}' -e 's/[&/\\]/\\\\&/g; s/\\n/\\\\&/g' <<<" & quoted form of txt & "; printf X)\"; printf %s \"${REPLY%$'\\n'X$'\\n'}\"" without altering line endings
end quoteSubst
[1] Some tweaks were necessary to make them work with do shell script; notably, process substitution (<(...)) is not supported; the workaround via <<<"$(...)" necessitated extra steps to accurately preserve trailing newlines in the input.
Once you've pasted above handlers into your script, here's how to apply them to your command:
do shell script "sed " & quoted form of ¬
("s/" & my quoteRegex(searchFor) & "/" & my quoteSubst(myData) & "/g") ¬
& " " & quoted form of inputFile & " > " & quoted form of outputFile
As for you original symptoms:
The weird part is, though, that it does write out the file with zero data in it.
This indicates that do shell script (a) was able to invoke the shell, (b) the shell parsed the command line without encountering a syntax error; if these conditions are met, an output redirection such as > outFile causes the target file to created as a zero-byte file, or, if it existed, to truncate it to a zero-byte file, BEFORE command execution begins.
If command execution then fails, the zero-byte file is left behind.
I actually get this error: No such file or directory, exit code 127
Exit code 127 indicates that the executable that is the 1st token of your command string could not be invoked, because it could not be found.
This is indeed what happened, because you mistakenly applied quoted form of to the sed executable name, its options, and the sed script together, which causes the entire resulting string to be interpreted as the executable name, which obviously fails.
Let's take a simplified example:
quoted form of "sed s/foo/bar/g file"
yields 'sed s/foo/bar/g file', including the enclosing single quotes.
Passing this string to the shell causes the shell to consider this string a single token that constitutes the executable path or filename. Obviously, no file named sed s/foo/bar/g file exists, so the command fails.
The solution, as demonstrated above, is to pass sed, its options, the script, as well as the input filename and the output filename as separate tokens.
Related
Is there an easy way using applescript to run a shell script that a) converts all carriage returns to unix linefeeds and then b) removes specific lines from the file? I have an very nice apple script/applet set up that will save a copy of the file with the lines removed (and I can drop multiple files on the applet), but if there are carriage returns, it fails.
Here is the shell script portion of my apple script:
**do shell script "sed -e '10,11d' -e '1,8d' " & thisFile & ">>" & donefile**
Can both needs be combined into one shell script?
I am an admitted noob and will be grateful for any help / education offered.
thank you!
sed can convert carriage return (\r) to newlines (\n), you need to add a part like this:
sed -e 's/\r/\n/g'
But this will probably change the line numbers for the following sed command you already have in place.
So the way to piece the new part together with what you have is probably something like this:
do shell script "sed -e 's/\r/\n/g' " & thisFile & " | sed -e '10,11d' -e '1,8d' ">>" & donefile
Here we first run the substitution of carriage return to linefeed on thisfile and then pipe the result to your sed command part from your question.
(Disclaimer: I have no clue about applescript I just copied from your question and I hope that the piping would work like this in applescript.)
Here below is the applescript:
do script ("aria2c -i /Users/mac/Downloads/aria2c\ \(1\).down") in currentTab
The expected result in shell would like this:
~$ aria2c -i /Users/mac/Downloads/aria2c\ \(1\).down
But it doesn't work...
In AppleScript a backslash must be escaped with a second one:
do script ("aria2c -i /Users/mac/Downloads/aria2c\\ \\(1\\).down") in currentTab
A smarter way is quoted form of, it magically adds all necessary backslashes / quotation characters
do script "aria2c -i " & quoted form of "/Users/mac/Downloads/aria2c (1).down" in currentTab
I know that Windows shell passes the whole line after an executable name to the executable, and it is task of the executable to parse it.
For instance,
C:\Users\osiv\Desktop\>perl -e "use File::Spec; print $_.' ' foreach (File::Spec->splitdir(\"C:\\Users\\osiv\\\"));"
should pass all characters after 'perl' to perl.exe found in a %PATH% value directory.
Explain me the output
C:\Users\osiv\Desktop\>perl -e "use File::Spec; print $_.' ' foreach (File::Spec->splitdir(\"C:\\Users\\osiv\\\"));"
Can't find string terminator '"' anywhere before EOF at -e line 1.
C:\Users\osiv\Desktop\>perl -e "use File::Spec; print $_.' ' foreach (File::Spec->splitdir(\"C:\\Users\\osiv\\\\"));"
Can't find string terminator '"' anywhere before EOF at -e line 1.
C:\Users\osiv\Desktop\>perl -e "use File::Spec; print $_.' ' foreach (File::Spec->splitdir(\"C:\\Users\\osiv\\\\\"));"
C: Users osiv
I expected that Perl parses the string passed by Windows shell by looking for strings which should have " at the start and the end. I escape them by \", and expected e.g. \"osiv\\\\\"));" to be parsed as osiv\\. But, \"osiv\\\"));" is not parsed as osiv\, so how it is actually parsed?
Explanation of cmd.exe, CreateProcess command line string metacharacters
Who cares? The exact rules are convoluted and hard to remember. Just avoid the problem by not using double quotes in your Perl one liners. You know you have ', q{} and qq{} available.
All of cmd’s transformations are triggered by the presence of one of the metacharacters (, ), %, !, ^, ", <, >, &, and |. " is particularly interesting: when cmd is transforming a command line and sees a ", it copies a " to the new command line, then begins copying characters from the old command line to the new one without seeing whether any of these characters is a metacharacter. This copying continues until cmd either reaches the end of the command line, runs into a variable substitution, or sees another ". In the last case, cmd copies a " to the new command line and resumes normal processing. This behavior is almost, but not quite like what CommandLineFromArgvW does with the same character; the difference is that cmd does not know about the \" sequence and begins interpreting metacharacters earlier than we would expect.
Also:
C:\> perl -MFile::Spec::Functions=splitdir -MFile::HomeDir -we "print qq{'$_' } for splitdir home"
'C:' 'Users' 'sinan'
perl -wE "use File::Spec; print \"'$_' \" for File::Spec->splitdir( \"C:\\Users\\osiv\\\\\" )"
'C:' 'Users' 'osiv' ''
which shows that you should omit the trailing directory separator.
A better method of quoting
While the " metacharacter cannot fully protect metacharacters in our command lines against unintended shell interpretation, the ^ metacharacter can. When cmd transforms a command line and sees a ^, it ignores the ^ character itself and copies the next character to the new command line literally, metacharacter or not. That’s why ^ works as the line continuation character: it tells cmd to copy a subsequent newline as itself instead of regarding that newline as a command terminator. If we prefix with ^ every metacharacter in an argument string, cmd will transform that string into the one we mean to use.
Trying to follow that, the best I can come up with is:
perl -wE ^"use File::Spec; print \^"'$_' \^" for File::Spec-^>splitdir^(\^"C:\\Users\\osiv\\\\\^"^) ^"
As I said, avoid " in one-liners, make use of ', q{}, and qq{}.
I have a file which contains URLs, one in each line. These URLs may contain spaces or other hazardous elements. I want to call a program with these urls, all of them at once.
urls.txt:
ptoto://domain/maybe with spaces & stuff 1
ptoto://domain/maybe with spaces & stuff 2
ptoto://domain/maybe with spaces & stuff 3
I want transform files like this to a call like:
myCommand "ptoto://domain/maybe with spaces & stuff 1" "ptoto://domain/maybe with spaces & stuff 2" "ptoto://domain/maybe with spaces & stuff 3"
Try the following :
while read -r; do
args+=("$REPLY")
done < textfile.txt
myCommand "${args[#]}"
Here, $REPLY is the default variable where read stores its result when no variable name is prompted. we use an array to store each line, and the double quotes forces to keep spaces & other characters.
"${args[#]}" display each element of the array
I am working with AppleScript and need to do this:
set TextToWrite to " #!/bin/bash cd "$( dirname "$0" )" java -server -Xmx4G -jar ./craftbukkit.jar" "
As you can see, the text I need to make into a string has quotes in it. How do I set
#!/bin/bash cd "$( dirname "$0" )" java -server -Xmx4G -jar ./craftbukkit.jar"
to an AppleScript string without the quotes messing it up?
To insert literal quotes into an Applescript string, you have to escape them, i.e.
set myString to "This is a \"quoted\" text."
AppleScript has the same convention as most languages, which is to use a backslash for escaping of special characters, of which there are only two: quotes and … backslash. See the section “Special string characters” of the AppleScript Language Guide.
The following syntax can also be used:
set aString to "quoted"
set myString2 to "This is a " & quoted form of aString & " text."
quoted form of (dirname as POSIX path)
set x to "He said \" Enter the matrix.\" "display dialog x
Just copy this into applescript the easiest way to understand.
Using quotes in applescript is quite easy you just need to make the line end and start in quotes
E.G
display dialog "hello world"
but when you decide to put a variable in the text you must use &
set my_name to "michael"
display dialog "hello" & my_name
thankyou