Replacing text with apostrophe text via sed in applescript - sed

I have an applescript to find and replace a number of strings. I ran in the problem of having a replacement string which contained & some time ago, but could get around it by putting \& in the replacement property list. However an apostrophe seems to be far more annoying.
Using a single apostrophe just gets ignored (replacement doesn't contain it), using \' gives a syntax error (Expected “"” but found unknown token.) and using \' gets ignored again. (You can keep doing that btw, even number gets ignored uneven gets syntax error)
I tried replacing the apostrophe in the actual sed command with double quotes (sed "s…" instead of sed 's…'), which works in the command line, but gives a syntax error in the script (Expected end of line, etc. but found identifier.)
The single quotes mess with the shell, the double quotes with applescript.
I also tried '\'' as was suggested here and '"'"' from here.
Basic script to get the type of errors:
set findList to "Thats.nice"
set replaceList to "That's nice"
set fileName to "Thats.nice.whatever"
set resultFile to do shell script "echo " & fileName & " | sed 's/" & findList & "/" & replaceList & " /'"

Try:
set findList to "Thats.nice"
set replaceList to "That's nice"
set fileName to "Thats.nice.whatever"
set resultFile to do shell script "echo " & quoted form of fileName & " | sed \"s/Thats.nice/That\\'s nice/\""
or to stick to your example:
set findList to "Thats.nice"
set replaceList to "That's nice"
set fileName to "Thats.nice.whatever"
set resultFile to do shell script "echo " & quoted form of fileName & " | sed \"s/" & findList & "/" & replaceList & "/\""
Explanation:
The sed statement is usually enclosed by single quotes like this:
set myText to "Hello"
set xxx to do shell script "echo " & quoted form of myText & " | sed 's/ello/i/'"
However, in this example you could have exluded the single quotes altogether.
set myText to "Hello"
set xxx to do shell script "echo " & quoted form of myText & " | sed s/ello/i/"
The unquoted sed statement will break down as soon a space is included.
set myText to "Hello"
set xxx to do shell script "echo " & quoted form of myText & " | sed s/ello/i there/"
--> error "sed: 1: \"s/ello/i\": unterminated substitute in regular expression" number 1
Since you can't include an apostrophe within a single quoted statement (even if you escape it), you can enclose the sed statement in double quotes like this:
set myText to "Johns script"
set xxx to do shell script "echo " & quoted form of myText & " | sed \"s/ns/n's/\""
EDIT
Lauri Ranta makes a good point that if your find or replace string contains escaped double quotes my answer won't work. Her solution is as follows:
set findList to "John's"
set replaceList to "\"Lauri's\""
set fileName to "John's script"
set resultFile to do shell script "echo " & quoted form of fileName & " | sed s/" & quoted form of findList & "/" & quoted form of replaceList & "/"

I'd also use text item delimiters. You don't have to include AppleScript's in the default scope or set the property back if it isn't used later.
set input to "aasearch"
set text item delimiters to "search"
set ti to text items of input
set text item delimiters to "replace"
ti as text
There's no easy way to escape the search or replace patterns if they can contain something that would be interpreted by sed.
set input to "a[a"
set search to "[a"
set replace to "b"
do shell script "sed s/" & quoted form of search & "/" & quoted form of replace & "/g <<< " & quoted form of input
If you have to use regular expressions, scripting languages like Ruby have methods for creating patterns from strings.
set input to "aac"
set search to "(a+)"
set replace to "\\1b"
do shell script "ruby -KUe 'print STDIN.read.chomp.gsub(Regexp.new(ARGV[0]), ARGV[1])' " & quoted form of search & " " & quoted form of replace & " <<< " & quoted form of input without altering line endings

Related

Apple script – replace with hyperlink in document without opening

I need to replace 400+ words with different hyperlinks in a rtf- or .docx-document.
I’ve made a script using keystrokes (cmd+f, esc etc), but the script takes forever and is not stable enough.
Using sed -i I’m able to do a replacement of the word, but not with hyperlink. Is this possible?
set theFile to choose file
set original to "foo"
set substitute to "VG"
set newlink to "https://www.vg.no"
do shell script "sed -i '' \"s|" & original & "|" & substitute & "|g\" " & quoted form of (POSIX path of theFile)
Here is something specific to try:
First, create a rich text document with the word 'foo' as its content (in TextEdit, as Word's output is an abomination). Save the file in the appropriate place and run this:
set theFile to ((path to desktop) as text) & "slink3.rtf"
set qptf to quoted form of POSIX path of theFile
set origStr to "foo"
set subStr to "VG"
set newlink to "https://www.vg.no"
do shell script "sed -i '' -e 's|" & origStr & "|" & subStr & "|' -e 's|VG|{{\\\\*\\\\fldinst{HYPERLINK \"https://www.vg.no/\"}}{\\\\fldrslt VG}}|' " & qptf
This expands to:
do shell script "sed -i '' -e 's|foo|VG|' -e 's|VG|{{\\\\*\\\\fldinst{HYPERLINK \"https://www.vg.no/\"}}{\\\\fldrslt VG}}|' '/Users/username/Desktop/slink3.rtf'"
The actual shell command which runs is:
% sed -i '' -e 's|foo|VG|' -e 's|VG|{{\\*\\fldinst{HYPERLINK "https://www.vg.no/"}}{\\fldrslt VG}}|' '/Users/username/Desktop/slink3.rtf'
What it does is first replace the string foo with the string VG, and then replace the string VG with VG as hyperlinked text.
NB TextEdit has a preference to display the raw rtf upon opening a file rather than the formatted text. If you do this with a document containing a single word, the structure is relatively clear. I recommend against even looking at a Word-generated document.
If you do this, you will see that the raw rtf uses a single backslash but both the shell and applescript require escaping which is why the script has \\\\.
Incidentally, I notice that you finish your sed search with 'g' but shouldn't this only run once per line? Consider removing it.
Obviously, I don't know your entire workflow but hopefully this matches the section you have posted.

Output is not generating while running the bash script [duplicate]

In Bash, what are the differences between single quotes ('') and double quotes ("")?
Single quotes won't interpolate anything, but double quotes will. For example: variables, backticks, certain \ escapes, etc.
Example:
$ echo "$(echo "upg")"
upg
$ echo '$(echo "upg")'
$(echo "upg")
The Bash manual has this to say:
3.1.2.2 Single Quotes
Enclosing characters in single quotes (') preserves the literal value of each character within the quotes. A single quote may not occur between single quotes, even when preceded by a backslash.
3.1.2.3 Double Quotes
Enclosing characters in double quotes (") preserves the literal value of all characters within the quotes, with the exception of $, `, \, and, when history expansion is enabled, !. The characters $ and ` retain their special meaning within double quotes (see Shell Expansions). The backslash retains its special meaning only when followed by one of the following characters: $, `, ", \, or newline. Within double quotes, backslashes that are followed by one of these characters are removed. Backslashes preceding characters without a special meaning are left unmodified. A double quote may be quoted within double quotes by preceding it with a backslash. If enabled, history expansion will be performed unless an ! appearing in double quotes is escaped using a backslash. The backslash preceding the ! is not removed.
The special parameters * and # have special meaning when in double quotes (see Shell Parameter Expansion).
The accepted answer is great. I am making a table that helps in quick comprehension of the topic. The explanation involves a simple variable a as well as an indexed array arr.
If we set
a=apple # a simple variable
arr=(apple) # an indexed array with a single element
and then echo the expression in the second column, we would get the result / behavior shown in the third column. The fourth column explains the behavior.
#
Expression
Result
Comments
1
"$a"
apple
variables are expanded inside ""
2
'$a'
$a
variables are not expanded inside ''
3
"'$a'"
'apple'
'' has no special meaning inside ""
4
'"$a"'
"$a"
"" is treated literally inside ''
5
'\''
invalid
can not escape a ' within ''; use "'" or $'\'' (ANSI-C quoting)
6
"red$arocks"
red
$arocks does not expand $a; use ${a}rocks to preserve $a
7
"redapple$"
redapple$
$ followed by no variable name evaluates to $
8
'\"'
\"
\ has no special meaning inside ''
9
"\'"
\'
\' is interpreted inside "" but has no significance for '
10
"\""
"
\" is interpreted inside ""
11
"*"
*
glob does not work inside "" or ''
12
"\t\n"
\t\n
\t and \n have no special meaning inside "" or ''; use ANSI-C quoting
13
"`echo hi`"
hi
`` and $() are evaluated inside "" (backquotes are retained in actual output)
14
'`echo hi`'
`echo hi`
`` and $() are not evaluated inside '' (backquotes are retained in actual output)
15
'${arr[0]}'
${arr[0]}
array access not possible inside ''
16
"${arr[0]}"
apple
array access works inside ""
17
$'$a\''
$a'
single quotes can be escaped inside ANSI-C quoting
18
"$'\t'"
$'\t'
ANSI-C quoting is not interpreted inside ""
19
'!cmd'
!cmd
history expansion character '!' is ignored inside ''
20
"!cmd"
cmd args
expands to the most recent command matching "cmd"
21
$'!cmd'
!cmd
history expansion character '!' is ignored inside ANSI-C quotes
See also:
ANSI-C quoting with $'' - GNU Bash Manual
Locale translation with $"" - GNU Bash Manual
A three-point formula for quotes
If you're referring to what happens when you echo something, the single quotes will literally echo what you have between them, while the double quotes will evaluate variables between them and output the value of the variable.
For example, this
#!/bin/sh
MYVAR=sometext
echo "double quotes gives you $MYVAR"
echo 'single quotes gives you $MYVAR'
will give this:
double quotes gives you sometext
single quotes gives you $MYVAR
Others explained it very well, and I just want to give something with simple examples.
Single quotes can be used around text to prevent the shell from interpreting any special characters. Dollar signs, spaces, ampersands, asterisks and other special characters are all ignored when enclosed within single quotes.
echo 'All sorts of things are ignored in single quotes, like $ & * ; |.'
It will give this:
All sorts of things are ignored in single quotes, like $ & * ; |.
The only thing that cannot be put within single quotes is a single quote.
Double quotes act similarly to single quotes, except double quotes still allow the shell to interpret dollar signs, back quotes and backslashes. It is already known that backslashes prevent a single special character from being interpreted. This can be useful within double quotes if a dollar sign needs to be used as text instead of for a variable. It also allows double quotes to be escaped so they are not interpreted as the end of a quoted string.
echo "Here's how we can use single ' and double \" quotes within double quotes"
It will give this:
Here's how we can use single ' and double " quotes within double quotes
It may also be noticed that the apostrophe, which would otherwise be interpreted as the beginning of a quoted string, is ignored within double quotes. Variables, however, are interpreted and substituted with their values within double quotes.
echo "The current Oracle SID is $ORACLE_SID"
It will give this:
The current Oracle SID is test
Back quotes are wholly unlike single or double quotes. Instead of being used to prevent the interpretation of special characters, back quotes actually force the execution of the commands they enclose. After the enclosed commands are executed, their output is substituted in place of the back quotes in the original line. This will be clearer with an example.
today=`date '+%A, %B %d, %Y'`
echo $today
It will give this:
Monday, September 28, 2015
Since this is the de facto answer when dealing with quotes in Bash, I'll add upon one more point missed in the answers above, when dealing with the arithmetic operators in the shell.
The Bash shell supports two ways to do arithmetic operation, one defined by the built-in let command and the other the $((..)) operator. The former evaluates an arithmetic expression while the latter is more of a compound statement.
It is important to understand that the arithmetic expression used with let undergoes word-splitting, pathname expansion just like any other shell commands. So proper quoting and escaping need to be done.
See this example when using let:
let 'foo = 2 + 1'
echo $foo
3
Using single quotes here is absolutely fine here, as there isn't any need for variable expansions here. Consider a case of
bar=1
let 'foo = $bar + 1'
It would fail miserably, as the $bar under single quotes would not expand and needs to be double-quoted as
let 'foo = '"$bar"' + 1'
This should be one of the reasons, the $((..)) should always be considered over using let. Because inside it, the contents aren't subject to word-splitting. The previous example using let can be simply written as
(( bar=1, foo = bar + 1 ))
Always remember to use $((..)) without single quotes
Though the $((..)) can be used with double quotes, there isn't any purpose to it as the result of it cannot contain content that would need the double quote. Just ensure it is not single quoted.
printf '%d\n' '$((1+1))'
-bash: printf: $((1+1)): invalid number
printf '%d\n' $((1+1))
2
printf '%d\n' "$((1+1))"
2
Maybe in some special cases of using the $((..)) operator inside a single quoted string, you need to interpolate quotes in a way that the operator either is left unquoted or under double quotes. E.g., consider a case, when you are tying to use the operator inside a curl statement to pass a counter every time a request is made, do
curl http://myurl.com --data-binary '{"requestCounter":'"$((reqcnt++))"'}'
Notice the use of nested double quotes inside, without which the literal string $((reqcnt++)) is passed to the requestCounter field.
There is a clear distinction between the usage of ' ' and " ".
When ' ' is used around anything, there is no "transformation or translation" done. It is printed as it is.
With " ", whatever it surrounds, is "translated or transformed" into its value.
By translation/ transformation I mean the following:
Anything within the single quotes will not be "translated" to their values. They will be taken as they are inside quotes. Example: a=23, then echo '$a' will produce $a on standard output. Whereas echo "$a" will produce 23 on standard output.
A minimal answer is needed for people to get going without spending a lot of time as I had to.
The following is, surprisingly (to those looking for an answer), a complete command:
$ echo '\'
whose output is:
\
Backslashes, surprisingly to even long-time users of bash, do not have any meaning inside single quotes. Nor does anything else.

Escape $ in powershell

I use the following to quickly login to RDP:
echo "Connecting to 192.168.1.100"
$Server="192.168.1.100"
$User="Administrator"
$Password="Admin$Password"
cmdkey /generic:TERMSRV/$Server /user:$User /pass:$Password
mstsc /v:$Server
Unfortunately AdminPassword does contain '$' character which breaks the thing. Is there a way to make it work?
Instead of using " " who take $x for a variable. Use ' ' and everything in it will be a character.
You can use the backtick character ` (to the left of the 1 key on US keyboards) to escape special characters - see About Special Characters.
This escapes the dollar sign as well, so your code would become:
$Password="Admin`$Password"

AppleScript to replace text in multiple files

I'm trying to come up with a general multi-purpose way of replacing text in multiple files through AppleScript. This solution is using Perl. Is there maybe a more elegant way of doing this?
set myFolder to choose folder with prompt "Choose a folder:"
tell application "Finder"
try
set txtFiles to (every file in entire contents of myFolder whose name ends with ".txt") as alias list
on error
try
set txtFiles to ((every file in entire contents of myFolder whose name ends with ".txt") as alias) as list
on error
set txtFiles to {}
end try
end try
set myFiles to txtFiles
end tell
repeat with CurrentFile in myFiles
set CurrentFile to CurrentFile as string
do shell script "perl -pi -e 's/replace/me/g; s/andme/too/g;' " & quoted form of (POSIX path of CurrentFile)
end repeat
Also, ideally, I'd like to make the Perl part a bit more readable, having each search/replace pattern on a separate line, but the do shell script in AppleScript seems to be unable to deal with line breaks, e.g.,
do shell script "perl -pi -e '
s/replace/me/g;
s/andme/too/g;
s/andhere/measwell/g;
' " & quoted form of (POSIX path of CurrentFile)
So essentially, is there a better/more elegant way of doing this?
Doesn't necessarily have to be with perl, yet for a non-expert I continue to find perl the easiest way for handling this, especially as it's great at regexes (the solution should be able to do regexes).
According to this, you could use
do shell script "perl -pi -e '" & ¬
" s/replace/me/g;" & ¬
" s/andme/too/g;" & ¬
" s/andhere/measwell/g;" & ¬
"' " & quoted form of (POSIX path of CurrentFile)
Pardon my lack of knowledge of AppleScript, but maybe you can even do something like the following:
set PerlProg to "" & ¬
"s/replace/me/g; " & ¬
"s/andme/too/g; " & ¬
"s/andhere/measwell/g;"
set PerlCmd to "perl -i -pe'" & PerlProg & "'"
do shell script PerlCmd & " " & quoted form of (POSIX path of CurrentFile)

Explain batch command please

I want to create a folder with the name of the current date and time.
After searching a lot i found this which actually works.
Can someone explain what these batch commands do?
set timestamp=%DATE:/=-%#%TIME::=-%
set timestamp=%timestamp: =%
mkdir "%timestamp%"
Insert echo statements between the lines and you can see what the value of timestamp is
set timestamp=%DATE:/=-%#%TIME::=-%
echo %timestamp%
set timestamp=%timestamp: =%
echo %timestamp%
mkdir "%timestamp%"
Basically, the code is just removing the forward slash from the date and the colon from time since those are not valid directory names replacing them with hypens.
Read set /? Environment variable substitution to get a better idea.
set timestamp=%DATE:/=-%#%TIME::=-%
That's a string replacement.
1st:
%DATE:/=-% Replaces "/" character to "-" character in the DATE variable
(See: Echo %DATE% on your console)
2nd:
Adds the "#" character to the string after the DATE var and before the TIME var.
3rd:
%TIME::=-% Replaces ":" character to "-" character.
(See: Echo %Time% on your console)
set timestamp=%timestamp: =%
Next in that replacement replaces itself spaces to any characarter (so deletes spaces), but really any space is given so is not necessary in your example code.
You can learn more about Variable string replacement here: http://ss64.com/nt/syntax-replace.html
Also you can simplify your code 'cause no need to setting the value first:
mkdir "%DATE:/=-%#%TIME::=-%"