Sed gives: sed: can't read : No such file or directory
Asked Answered
H

5

87

I have the following bash script which repeats for each image found. It needs to iterated over all html, css and js files, and replace all occurrences of an image within that file.

 for image in app/www/images-theme-dark/*.png
    do
        echo "installing icon" $image

        # extract filename from iconpath
        iconfile=$(basename $image)
        iconPath="images/"$(basename $image)

        # replace paths in all files containing icon paths
        find app/www -type f \( -name "*.html" -or -name "*.css" -or -name "*.js" \
                            -or -name "*.appcache" \)  \
            -exec sed -i '' -e 's|$iconPath|images-theme-dark/$iconfile|g' "{}" \;

    done

However when I run the script sed gives:

sed: can't read : No such file or directory

On StackOverflow I've found sed: can't read : No such file or directory But I already had quotes around {}

When I echo the sed command and and execute it on the command line manually there is no error.

I am using GNU sed v4.2.2 on Raspbian GNU/Linux 8.0 (jessie)

Does someone see what could be wrong here?

Halfandhalf answered 2/4, 2017 at 18:1 Comment(11)
Btw: see: Difference between single and double quotes in bashLongobard
What is that '' after sed -i?Drawstring
@Drawstring it prevents sed to create a backup file and replaces directly in the file insteadHalfandhalf
Please add OS and sed version to your question.Longobard
Replace -i '' by -i. For your next problem see my first comment.Longobard
Dear Osi, Melpomene asked you a question with the intention that you will consider it carefully, for example by reading the manual page. You think that -i '' "prevents sed to create a backup file and replaces directly in the file instead", but have your actually checked that what you think is correct? Hint: you are wrong.Legislator
@Legislator to be honest I didn't I took it from https://mcmap.net/q/243221/-sed-without-backup-file thanks for pointing out!Halfandhalf
@osi: syntax of -i is one difference between GNU sed and sed from mac os.Longobard
@osi: -i means in-place, that is, edit in the file directly. -i '' means edit in place a file whose name is the empty string. Since probably you don't actually have a file whose name is the empty string, sed complains that it cannot read it.Legislator
@Yunnosh: The syntax requires the suffix of the backup copy immediately after -i, not as a separate argument. For example, sed -i.bak will edit a file in place and make a backup by appending .bak. A separate argument is taken as the name of a file to edit. Tested with GNU sed 4.2.2.Legislator
@Legislator You are right (blushing). Can't recreate what I tested. Thanks. One of the things which got me off track is that the script, with -e, can be between file names. Now I think your comment should be an answer; and be voted up.Mile
M
125

(Compiling an answer from comments, the know-how is by melpomene and AlexP.)

What is that '' after sed -i?

-i means in-place, that is, edit in the file directly.
-i '' means edit in place a file whose name is the empty string.
Since there probably is no file whose name is the empty string, sed complains that it cannot read it.

Note 1 platform dependency:
The syntax of -i is one difference between GNU sed and sed from mac os.

Note 2 "usual" order of arguments:
The -e switch to indicate the sed code allows having it in between file names.
This is a trap (in which I for example got caught embarassingly), by making you trip over your expectations of what you find where in an sed command line.
It allows
sed -i filename -e "expression" AnotherFileName
which is an unintentionally camouflaged version of
sed -i'NoExtensionGiven' "expression" filename AnotherFileName.

Mile answered 17/4, 2017 at 14:29 Comment(0)
A
107

For support on both OSX and Linux, I use a simple if check to see if the bash script is running on OSX or Linux, and adjust the command's -i argument based on that.

if [[ "$OSTYPE" == "darwin"* ]]; then
  sed -i '' -e 's|$iconPath|images-theme-dark/$iconfile|g' "{}"
else
  sed -i -e 's|$iconPath|images-theme-dark/$iconfile|g' "{}"
fi
Argentic answered 3/9, 2019 at 7:16 Comment(1)
The Linux nomenclature works w/ msys too on Windows. Thanks for the tip Acidic.Musketry
E
11

In my bash scripts I use something like that (to support both MacOS and Linux distributions):

SEDOPTION=
if [[ "$OSTYPE" == "darwin"* ]]; then
  SEDOPTION="-i ''"
fi

sed $SEDOPTION "/^*/d" ./file
Eberle answered 23/3, 2021 at 13:3 Comment(3)
Please explain the additional insight this provides on top of existing answers, especially the one by @Acidic9. I fail to see the functional difference between your answer and that one. Also, "I use something like this" provides no explanation to this otherwise code-only answer. In short please make your contribution more obvious, to avoid the impression of having copied and minimally, functionally irrelevantly, changed it.Mile
storenth's answer is more portable and becomes increasingly better the more sed commands you are using, though I needed the -i option for non-macOS. That said, this solution had a weird quirk on my macOS by appending the quotation marks from $SEDOPTION to the filename. I had to resort to the following hackery to prevent that... I tried many other things like piping xargs, swapping single and double quotes, backticks, etc. but this is what worked for me (\x27 represents single-quote): if [[ "$OSTYPE" == "darwin"* ]]; then SEDOPTION='-i \x27\x27'; else SEDOPTION='-i'; fi;Denten
This assumes that sed is that of base macOS, and can break if not (for instance if sed comes from MacPorts). A bulletproof solution is more complicated (checking the path of sed might not be enough…).Performative
O
0

In my case, I was using Ubuntu on Vagrant/Virtualbox, and I had to add

sleep 5

before the sed -command. It seems that the previous command had not flushed the disk fast enough, and was giving the errors when run fast in a script.

The other symptom was that if you ran the same command manually, it worked just fine.

Orrin answered 22/4 at 18:59 Comment(0)
I
-7

For me, it got fixed by restarting

wsl --shutdown
Irremissible answered 29/8, 2023 at 1:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.