do shell script "tr '\r' '\n'

Hello again all you AppleScript brains.
I have searched for an answer to this, but can find none. According to The AppleScript developer archive here :
https://developer.apple.com/library/archive/technotes/tn2065/_index.html

doing this in an Applescript should be possible :

set f to choose file
do shell script "tr '\r' '\n' < " & quoted form of POSIX path of f & " | grep something"

This is pretty much what I want to do, to parse classic Mac files before AWKing them !

The snag is that if you paste this into Script Editor and compile it, both \r and \n just disappear in favour of newlines ! The script turns into this :

set f to choose file
do shell script "tr '
' '
' < " & quoted form of POSIX path of f & " | grep something"

If you replace \r and \n with \r and \n, it literally replaces all the "r"s in a text with "n"s… not ideal !!

So, is it that Apple’s developer page is out of date, and there’s some new way of doing this, or did it just never work in the first place? If if never did work, then how could I achieve the same result ?
Thanks in advance for your help.

Hi.

The strings in the “tr” command are strings within the string representing the shell script command, so the escaping probably needs to be doubled:

set f to choose file
do shell script "tr '\\\\r' '\\\\n' < " & quoted form of POSIX path of f & " | grep something"

Yup !! That’s totally it :slight_smile: Is there anything you guys don’t know about AppleScript :wink:

Thanks very much for you prompt answer.

Oooooops !! I take back what I said… not about the thanks, but about it being the answer ! As someone below pointed out, it replaces "r"s with "n"s, just like the double-slash version does :frowning:

  1. This is normal behaviour of “\r” (return constant) and “\n” (linefeed constant), so it should work as is.
  2. If you don’t like this presentation of Script Editor, then you can use this equivalent form:

set f to choose file
do shell script "tr " & quoted form of return & space & quoted form of linefeed & ¬
	" < " & quoted form of POSIX path of f & " | grep something"

I was just testing this script and it seems to me that it also replaces any normal “r” into a “n”. For normal I mean a text character.

In my notes I have this format:
"tr ‘\r/’ ‘\n/’

ButI might be wrong.

L.

I tested all scripts here (mine too). All of them doesn’t replace “\r” with “\n”. The Nigel’s script replaces “\r” with “\n”, but it also replaces every “r” with “n”.

  1. Instead “\r” replaces the “\n” in original script and in mine !!!

So, a solution has not yet been found.

Hi ldicroce.

No, your’e right. I didn’t actually test the code before posting. It seems to need another two backslashes in each term. I’m not clear why.

set f to choose file
do shell script "tr '\\\\\\r' '\\\\\\n' < " & quoted form of POSIX path of f & " | grep something"

Once you get into multiple-level escaping, its probably best to use literal characters, if possible, as in KniazidisR’s example above.

I think Fred’s changing the returns to linefeeds for the benefit of the “grep” command. But if this was being done in order to return a text with linefeeds to the outside world, the ‘do shell script’ command itself would need an extra parameter, because it normally converts all linefeeds in its output to returns!

set f to choose file
do shell script ("tr " & quoted form of return & space & quoted form of linefeed & ¬
	" < " & quoted form of POSIX path of f) without altering line endings

If you run this code I believe that the result indicate that the best way to replace return/linefeed is using: tr ‘\r/’ ‘\n/’
Looking at the different options of visualisation, all seem to indicate that this: tr ‘\r/’ ‘\n/’ is the most reliable one.

set f1 to "/Users/ldicroce/Desktop/Test1.txt"
set f2 to "/Users/ldicroce/Desktop/Test2.txt"
set f3 to "/Users/ldicroce/Desktop/Test3.txt"
# Writnig the initial file with both return and linefeed
set outputString to "Luciano" & return & "Tarc" & linefeed & linefeed
WriteToTextFile(outputString, f1)

# replacing return with linefeed using KniazidisR code
set myNewText to do shell script "tr " & quoted form of return & space & quoted form of linefeed & ¬
	" < " & quoted form of POSIX path of f1
# saving this new version
WriteToTextFile(outputString, f2)

# replacing return with linefeed and saving this new version
set myConversion to do shell script "tr '\\r/' '\\n/'  < " & (f1's POSIX path) & " > " & (f3's POSIX path)

# to visualize the ending in the Terminal 
tell application "Terminal"
	do script "cat -et " & f1's POSIX path in window 1
	do script "cat -et " & f2's POSIX path in window 1
	do script "cat -et " & f3's POSIX path in window 1
	
	do script "od -a " & f1's POSIX path in window 1
	do script "od -a " & f2's POSIX path in window 1
	do script "od -a " & f3's POSIX path in window 1
	
	do script "hexdump -c " & f1's POSIX path in window 1
	do script "hexdump -c " & f2's POSIX path in window 1
	do script "hexdump -c " & f3's POSIX path in window 1
end tell

on WriteToTextFile(someText, posixPathOrAlias) -- using AS Path can be both Aias and Posix path
	set fileDescriptor to (open for access posixPathOrAlias with write permission)
	try
		set eof fileDescriptor to 0
		write someText to fileDescriptor -- as «class utf8»
		close access fileDescriptor
	on error errMsg number errNbr
		close access fileDescriptor
		error errMsg number errNbr
	end try
end WriteToTextFile

without altering line endings
Thanks you, Nigel, your last snippets is long-awaited solution. That’s what experience means!

NOTE: you last “escaping” snippet should include without altering line endings too. Test:


set aText to "I doesn't tested the following," & return & "but, I think, that right escaping syntax" & linefeed & "should be like this:"
set f to alias (((path to desktop folder) as text) & "unspecified.txt")-- It is created manually
set eof of f to 0
write aText to f

set editedText to (do shell script "tr '\\\\\\r' '\\\\\\n' < " & quoted form of POSIX path of f without altering line endings)

Returning to original script. It works too, when add without altering line endings:


set aText to "I doesn't tested the following," & return & "but, I think, that right escaping syntax" & linefeed & "should be like this:"
set f to alias (((path to desktop folder) as text) & "unspecified.txt") -- It is created manually
set eof of f to 0
write aText to f

set editedText to (do shell script "tr '\r' '\n' < " & quoted form of POSIX path of f without altering line endings)

This is also works using foundation (I guess I got it from Shane)

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
use framework "Foundation"

# using Fundations 
property NSRegularExpressionSearch : a reference to 1024
property NSString : a reference to current application's NSString
set mytext to "Luciano" & return & "Tarc" & linefeed & linefeed

set f5 to "/Users/ldicroce/Desktop/Test5.txt"
set f6 to "/Users/ldicroce/Desktop/Test6.txt"

WriteToTextFile(mytext, f5)
# set a to "\r"
set a to "
"
# set b to "\n"
set b to "
"
set aString to NSString's stringWithString:mytext
set mytext to (aString's stringByReplacingOccurrencesOfString:a withString:b) as text

WriteToTextFile(mytext, f6)

# to visualize:  "\r" (CR) will appear as ^M;  "\r\n" sequences  as ^M or  ^M$; " \n" as $;  tab charsas ^I
tell application "Terminal"
	do script "cat -et " & f5's POSIX path in window 1
	do script "cat -et " & f6's POSIX path in window 1
end tell


on WriteToTextFile(someText, posixPathOrAlias) -- using AS Path can be both Aias and Posix path
	set fileDescriptor to (open for access posixPathOrAlias with write permission)
	try
		set eof fileDescriptor to 0
		write someText to fileDescriptor -- as «class utf8»
		close access fileDescriptor
	on error errMsg number errNbr
		close access fileDescriptor
		error errMsg number errNbr
	end try
end WriteToTextFile

When returning the modified file text directly from do shell script yes. But in the snippet, the change from returns to linefeeds is simply so that the “grep” command in the same shell script will recognise the line boundaries and return just the line(s) containing the search term. do shell script only enforces returns in its final output (unless without altering line endings is used as well).

set txt to "1. Here" & return & "2. is" & return & "3. something"
log "grep with returns:"
log (do shell script "grep 'something' <<< " & quoted form of txt)
log ""

set txt to "1. Here" & linefeed & "2. is" & linefeed & "3. something"
log "grep with linefeeds:"
log (do shell script "grep 'something' <<< " & quoted form of txt)

I think you’re getting escape happy. This works:

 do shell script "tr '\\r' '\\n' < " & quoted form of POSIX path of f without altering line endings

The extra four backslashes result in a single escaped backslash, so you were changing a backslash to a backslash, as well as a return to a linefeed.

If you’re using Script Debugger, control click in the results pane and choose Show Invisibles.

You could use AppleScriptObjC code instead:

use AppleScript version "2.5" -- macOS 10.11 or later
use framework "Foundation"
use scripting additions

set f to choose file
set theString to current application's NSString's stringWithContentsOfURL:f encoding:(current application's NSMacOSRomanStringEncoding) |error|:(missing value)
set theString to (theString's stringByReplacingOccurrencesOfString:return withString:linefeed) as text

That’s certainly more verbose, but quite a bit faster. And you could then do your grep stuff in it as well.

What you sad now means: the original code of OP from developer page & my code in post #4 should work correctly. What I talked about in the same post. I made inaccurate conclusions later, when I started testing, folding Grep command.
But, anyway, it was useful for me to find out how to solve the problem when the tr command returns the result directly (without grep command, in this case).

Ah. That would explain it. :rolleyes:

Nice! I din’t know !

Wow ! You learn so many things here ! I’ve yet to test your various proposals, so I’ll come back with my conclusions later, after testing. Thanks to all of you for your time and answers. I didn’t realise an excerpt from an Apple Developer page would start such a debate. I think however the the debate will most certainly help others too, so most worthwhile :slight_smile:


OK. I’ve tested these solutions, and all seem to work fine. Shane’s version does indeed appear do be a little faster, but then again, it goes places that I’m not sure I wish to go myself, for the moment anyway :slight_smile:

Thank you all again for your pertinent and learned suggestions.