3

I was trying to make a Finder service to easily convert text encoding of some files. Because the default charset for Simplified Chinese in Windows is the Chinese national standard GB18030 (not the UTF-8 used on Mac).

With some help from the answers at services - Automator Get Filename of Selected File - Ask Different, I set up Service receives selected: Files or folders in:Finder

Then, I made this Shell script in Automator:

for f in "$@"
do
    iconv -f gb18030 -t utf-8 f > f.new
done

However, when I run the service when selecting f, I don't see the newly created f.new in Finder. I guess I have set the output path wrong. But I don't know what is the right way to fix it.

Automator screenshot

  • 1
    To make it work, the Pass input: in the procedure should be as arguments instead of to stdin. – jackxujh Dec 2 '17 at 19:16
  • I've modified my answer to address a comment made by Gordon Davisson and suggest you use the modified answer instead. – user3439894 Dec 3 '17 at 2:23
3

Change:

for f in "$@"
do
    iconv -f gb18030 -t utf-8 f > f.new
done

To:

for f in "$@"; do
    if [[ ! $(basename "$f") =~ .*\..* ]]; then
        iconv -f gb18030 -t utf-8 < "$f" > "${f}-new"
    else
        iconv -f gb18030 -t utf-8 < "$f" > "${f%.*}-new.${f##*.}"
    fi
done

And set Pass input: to as arguments on the Run Shell Script action.


To address the comment made by Gordon Davisson to handle a filename with no extension, I've modified the code in my answer above.

The code tests the filename portion of the fully qualified pathname passed to the Run Sell Script action using a regex to see if it has an extension, or more literally a . as part of the filename, and if there is no . in the filename it process the if branch, otherwise it processes the else branch.

Also note that using a glob instead of a regex, e.g.:

if [[ ! $(base name "$f") == *.* ]]; then

Would also work to test for an extension. Either way the new fully qualified pathname will appropriately follow one of these two examples:

  • /path/to/filename becomes: /path/to/filename-new
  • /path/to/filename.ext becomes: /path/to/filename-new.ext

Note: This answer assumes fully qualified pathnames do not contain null characters and or carriage returns and or linefeeds. IMO Proper pathnames do not contains such characters and I will not test for them.

  • @jackxujh, I updated my answer. Seems you need to direct the input file into the command and then redirect the output to the new file. The old and new file should be in the same location now. As well as what you noted in your comment to your question. – user3439894 Dec 2 '17 at 19:17
  • After I changed the pass parameters setting, the previous edit of the answer (without <) started to work fine. And then I saw you added the < mark. And it also works! – jackxujh Dec 2 '17 at 19:19
  • Now the service makes file.txt.new with converted text encoding when run, but ideally file-new.txt would be even better. Is that possible too? Thanks! – jackxujh Dec 2 '17 at 19:22
  • Yes, it actually works either way however it does need to be Pass input: as arguments, which I didn't look at in your picture, because I automatically use that when running a for loop. – user3439894 Dec 2 '17 at 19:22
  • 1
    "${f%.*}-new.${f#*.}" only works on filenames with exactly one period character (in directories that don't have periods in the name). Doing this right is surprisingly hard, but "${f%.*}-new.${f##*.}" (note the double-#) handles multiple periods properly (though it still gets confused by filenames without periods). – Gordon Davisson Dec 2 '17 at 21:46

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .