Append to files Announcing the arrival of Valued Associate #679: Cesar Manara Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern) 2019 Community Moderator Election Results Why I closed the “Why is Kali so hard” questionWhy is looping over find's output bad practice?Have backticks (i.e. `cmd`) in *sh shells been deprecated?How do I append text to the beginning and end of multiple text files in Bash?sed insert in the beginning of multiple files is not workingHow to pass an argument from a bash script to 'x-terminal-emulator -e bash -c'?How to append extension to files with certain filename formatFind files and recursively append text to themsed backreference: get each line and append it to end of linesed append a text with many lines after matching of multiple strings while the text remains many lines in sed commandHow to copy strings from middle of lines (between strings) to the end of linesFind words after specific symbol on lineHow to sed chunks text from a stream of files from find
Generate an RGB colour grid
T-test, ANOVA or Regression, what's the difference?
Is there such thing as an Availability Group failover trigger?
Using audio cues to encourage good posture
Why are std::future and std::promise not final?
How come Sam didn't become Lord of Horn Hill?
How can I use the Python library networkx from Mathematica?
Circuit to "zoom in" on mV fluctuations of a DC signal?
For a new assistant professor in CS, how to build/manage a publication pipeline
Is there a kind of relay only consumes power when switching?
Is it cost-effective to upgrade an old-ish Giant Escape R3 commuter bike with entry-level branded parts (wheels, drivetrain)?
Why do we bend a book to keep it straight?
Amount of permutations on an NxNxN Rubik's Cube
How to tell that you are a giant?
Novel: non-telepath helps overthrow rule by telepaths
Denied boarding although I have proper visa and documentation. To whom should I make a complaint?
8 Prisoners wearing hats
Find the length x such that the two distances in the triangle are the same
Is it ethical to give a final exam after the professor has quit before teaching the remaining chapters of the course?
When a candle burns, why does the top of wick glow if bottom of flame is hottest?
What is this building called? (It was built in 2002)
What do you call the main part of a joke?
What is homebrew?
Do square wave exist?
Append to files
Announcing the arrival of Valued Associate #679: Cesar Manara
Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern)
2019 Community Moderator Election Results
Why I closed the “Why is Kali so hard” questionWhy is looping over find's output bad practice?Have backticks (i.e. `cmd`) in *sh shells been deprecated?How do I append text to the beginning and end of multiple text files in Bash?sed insert in the beginning of multiple files is not workingHow to pass an argument from a bash script to 'x-terminal-emulator -e bash -c'?How to append extension to files with certain filename formatFind files and recursively append text to themsed backreference: get each line and append it to end of linesed append a text with many lines after matching of multiple strings while the text remains many lines in sed commandHow to copy strings from middle of lines (between strings) to the end of linesFind words after specific symbol on lineHow to sed chunks text from a stream of files from find
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
I have a directory full of files. My goal is to append text to the beginning of the file. The text that goes at the beginning is the same for each file.
This is my attempt
#!/bin/bash
for file in `find . -type f -executable`;do
sed '/#!/bin/bash/a Hello Word'
done
My script does nothing but crash
shell-script files sed find
add a comment |
I have a directory full of files. My goal is to append text to the beginning of the file. The text that goes at the beginning is the same for each file.
This is my attempt
#!/bin/bash
for file in `find . -type f -executable`;do
sed '/#!/bin/bash/a Hello Word'
done
My script does nothing but crash
shell-script files sed find
2
Have a look at this question. Looping over find's output is a bad practice.
– Iñaki Murillo
Nov 10 '16 at 8:41
add a comment |
I have a directory full of files. My goal is to append text to the beginning of the file. The text that goes at the beginning is the same for each file.
This is my attempt
#!/bin/bash
for file in `find . -type f -executable`;do
sed '/#!/bin/bash/a Hello Word'
done
My script does nothing but crash
shell-script files sed find
I have a directory full of files. My goal is to append text to the beginning of the file. The text that goes at the beginning is the same for each file.
This is my attempt
#!/bin/bash
for file in `find . -type f -executable`;do
sed '/#!/bin/bash/a Hello Word'
done
My script does nothing but crash
shell-script files sed find
shell-script files sed find
edited Apr 13 at 15:04
Rui F Ribeiro
42.1k1484142
42.1k1484142
asked Nov 10 '16 at 8:20
K.UK.U
205
205
2
Have a look at this question. Looping over find's output is a bad practice.
– Iñaki Murillo
Nov 10 '16 at 8:41
add a comment |
2
Have a look at this question. Looping over find's output is a bad practice.
– Iñaki Murillo
Nov 10 '16 at 8:41
2
2
Have a look at this question. Looping over find's output is a bad practice.
– Iñaki Murillo
Nov 10 '16 at 8:41
Have a look at this question. Looping over find's output is a bad practice.
– Iñaki Murillo
Nov 10 '16 at 8:41
add a comment |
3 Answers
3
active
oldest
votes
#!/bin/bash
for file in `find . -type f -executable`;do
sed '/#!/bin/bash/a Hello Word'
fi
done
This script has a great number of problems.
First, it's not a valid Bash script, because you have fi with no corresponding if.
Stylistically (after removing the fi line), I would remove the empty line before done and add a space before do. But that's relatively trivial.
Now, as to best practices, you are using backticks for command substitution rather than the recommended modern form, $(...). Backticks are supported purely for historical reasons and are not recommended for any new scripts; see:
- Have backticks (i.e. `cmd`) in *sh shells been deprecated?
You have a robustness issue in that you are looping over the output of find—a very bad idea, and totally unnecessary. Your script will break on any filenames containing whitespace or special characters. See:
Why is looping over find's output bad practice?)
If you want your script to be portable, you should stick to POSIX specified features whenever possible. In particular the -executable primary to find is not specified by POSIX. Consider using -perm +700 instead.
Also in the realm of portability, using the "append" command to Sed (a) without a following <newline> sequence works in GNU Sed, but is not standard.
You set the file variable in your for loop to the name of each file in turn (assuming no special characters or whitespace in the filenames, which will cause the file variable to contain something which is not a filename), but you never actually use the file variable.
Your Sed command is not given any file to run on, so it will attempt to run on standard input. Thus when you run the script it will simply wait for input.
Your Sed script itself is incorrect, independent of the fact that it's missing a filename to operate on.
If you use / as a delimiter for a regex (which is most usual), you need to backslash-escape all instances of / which occur within the regex. The only portion of your command which will be read as a regex is /#!/, and the rest (starting with bin) will be interpreted as a Sed command.
Instead, the usual solution would be to replace each / other than the final regex delimiter with /. (I see that you escaped only the last slash, which should not be escaped.)
There is a little-known feature in Sed, which you could use to your advantage here. Any character (other than a backslash or newline) can be used as a regex delimiter, rather than only using a slash. So rather than using /#!/bin/bash/ as a Sed address, you could use the equivalent :#!/bin/bash:
Now if you've handled all of the above points, you will have a working script. It may not do what you want it to do, but it will actually do something. Such a script would look like this:
#!/bin/bash
find . -type f -perm -700 -exec sed ':#!/bin/bash:a
Hello World' +
What does this script do? It searches the current directory recursively for all files with the executable bit set (for the owner), and for each such file, prints the entire file with the text Hello World appended after any lines which contain the text #!/bin/bash.
Sed is not actually designed for editing files in place; it is the Stream EDitor. GNU Sed will allow you to edit files in place using the -i switch, but I would just use the standard tool ex for file editing.
But there is another point here. If you want to add the line Hello World in a Bash script, it won't actually do anything, as Hello is not a valid command name. Perhaps what you want is to print the text "Hello World" in the Bash script, in other words to add echo "Hello World, which could make sense.
Now we're into the realm of clarifying more exactly what your script is supposed to do.
The Final Script
So my more exact statement of the specifications for this script are:
- The script shall find all regular files in the current directory (or any subdirectory recursively) which have the executable bit set for the owner.
- For each such file, the script shall check whether the first line of the file exactly equals the string
#!/bin/bash. - Only for files with this exact first line, the script shall insert the exact text
echo "Hello World", followed by a newline character, after the first line of the file. (This change shall be saved to the file, not printed to standard out.)
Here is a script matching those exact specifications, using only POSIX tools and features:
#!/bin/sh
find . -type f -perm -700 -exec sh -c '
for f
do
head -n 1 "$f" | grep -qFx "#!/bin/bash" &&
printf "%sn" "1a" "echo "Hello World"" . x | ex "$f"
done
' find-sh +
Hi, when I run this script I got : find: invalid mode ‘+700’
– K.U
Nov 10 '16 at 23:26
I'm using Virtual Machine on MacOs and the version is 4.4.0-45-generic I think.
– K.U
Nov 10 '16 at 23:43
Even it prints out that error the code still append : echo "Hello World" to my executable files
– K.U
Nov 10 '16 at 23:48
@K.U, fixed. Use-700, not+700.
– Wildcard
Nov 11 '16 at 0:04
it appends "echo "Hello World" " instead of just "Hello World". Should I remove one of the " "
– K.U
Nov 11 '16 at 0:10
add a comment |
what you are trying to achieve ? to find out the executable scripts, use the below command
find . -type f -perm /u+x,g+x,o+x | while read file
do
filename=$(echo $file | awk -F/ 'print $NF')
echo "File Name : $filename"
done
If you are trying append Hello World after the shebang line, then your sed command should be
sed '/#!/bin/bash/a Hello Word' $file
if you want to make the changes in the file itself, then add -i in sed command
Hi, I'm trying to append Hello World to executable files in a directory. I know how to find executable files, but I don't quite know how I could append text to those file
– K.U
Nov 10 '16 at 23:33
When I run your code to find executables file I got: File Name : ./insert.sh Is there a way I can only get: File Name : insert.sh
– K.U
Nov 10 '16 at 23:39
modified the answer
– Kamaraj
Nov 11 '16 at 3:35
add a comment |
find . -type f -executable -exec sed '/^#!/bin/bash/a Hello World' ;
add a comment |
Your Answer
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "106"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f322255%2fappend-to-files%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
#!/bin/bash
for file in `find . -type f -executable`;do
sed '/#!/bin/bash/a Hello Word'
fi
done
This script has a great number of problems.
First, it's not a valid Bash script, because you have fi with no corresponding if.
Stylistically (after removing the fi line), I would remove the empty line before done and add a space before do. But that's relatively trivial.
Now, as to best practices, you are using backticks for command substitution rather than the recommended modern form, $(...). Backticks are supported purely for historical reasons and are not recommended for any new scripts; see:
- Have backticks (i.e. `cmd`) in *sh shells been deprecated?
You have a robustness issue in that you are looping over the output of find—a very bad idea, and totally unnecessary. Your script will break on any filenames containing whitespace or special characters. See:
Why is looping over find's output bad practice?)
If you want your script to be portable, you should stick to POSIX specified features whenever possible. In particular the -executable primary to find is not specified by POSIX. Consider using -perm +700 instead.
Also in the realm of portability, using the "append" command to Sed (a) without a following <newline> sequence works in GNU Sed, but is not standard.
You set the file variable in your for loop to the name of each file in turn (assuming no special characters or whitespace in the filenames, which will cause the file variable to contain something which is not a filename), but you never actually use the file variable.
Your Sed command is not given any file to run on, so it will attempt to run on standard input. Thus when you run the script it will simply wait for input.
Your Sed script itself is incorrect, independent of the fact that it's missing a filename to operate on.
If you use / as a delimiter for a regex (which is most usual), you need to backslash-escape all instances of / which occur within the regex. The only portion of your command which will be read as a regex is /#!/, and the rest (starting with bin) will be interpreted as a Sed command.
Instead, the usual solution would be to replace each / other than the final regex delimiter with /. (I see that you escaped only the last slash, which should not be escaped.)
There is a little-known feature in Sed, which you could use to your advantage here. Any character (other than a backslash or newline) can be used as a regex delimiter, rather than only using a slash. So rather than using /#!/bin/bash/ as a Sed address, you could use the equivalent :#!/bin/bash:
Now if you've handled all of the above points, you will have a working script. It may not do what you want it to do, but it will actually do something. Such a script would look like this:
#!/bin/bash
find . -type f -perm -700 -exec sed ':#!/bin/bash:a
Hello World' +
What does this script do? It searches the current directory recursively for all files with the executable bit set (for the owner), and for each such file, prints the entire file with the text Hello World appended after any lines which contain the text #!/bin/bash.
Sed is not actually designed for editing files in place; it is the Stream EDitor. GNU Sed will allow you to edit files in place using the -i switch, but I would just use the standard tool ex for file editing.
But there is another point here. If you want to add the line Hello World in a Bash script, it won't actually do anything, as Hello is not a valid command name. Perhaps what you want is to print the text "Hello World" in the Bash script, in other words to add echo "Hello World, which could make sense.
Now we're into the realm of clarifying more exactly what your script is supposed to do.
The Final Script
So my more exact statement of the specifications for this script are:
- The script shall find all regular files in the current directory (or any subdirectory recursively) which have the executable bit set for the owner.
- For each such file, the script shall check whether the first line of the file exactly equals the string
#!/bin/bash. - Only for files with this exact first line, the script shall insert the exact text
echo "Hello World", followed by a newline character, after the first line of the file. (This change shall be saved to the file, not printed to standard out.)
Here is a script matching those exact specifications, using only POSIX tools and features:
#!/bin/sh
find . -type f -perm -700 -exec sh -c '
for f
do
head -n 1 "$f" | grep -qFx "#!/bin/bash" &&
printf "%sn" "1a" "echo "Hello World"" . x | ex "$f"
done
' find-sh +
Hi, when I run this script I got : find: invalid mode ‘+700’
– K.U
Nov 10 '16 at 23:26
I'm using Virtual Machine on MacOs and the version is 4.4.0-45-generic I think.
– K.U
Nov 10 '16 at 23:43
Even it prints out that error the code still append : echo "Hello World" to my executable files
– K.U
Nov 10 '16 at 23:48
@K.U, fixed. Use-700, not+700.
– Wildcard
Nov 11 '16 at 0:04
it appends "echo "Hello World" " instead of just "Hello World". Should I remove one of the " "
– K.U
Nov 11 '16 at 0:10
add a comment |
#!/bin/bash
for file in `find . -type f -executable`;do
sed '/#!/bin/bash/a Hello Word'
fi
done
This script has a great number of problems.
First, it's not a valid Bash script, because you have fi with no corresponding if.
Stylistically (after removing the fi line), I would remove the empty line before done and add a space before do. But that's relatively trivial.
Now, as to best practices, you are using backticks for command substitution rather than the recommended modern form, $(...). Backticks are supported purely for historical reasons and are not recommended for any new scripts; see:
- Have backticks (i.e. `cmd`) in *sh shells been deprecated?
You have a robustness issue in that you are looping over the output of find—a very bad idea, and totally unnecessary. Your script will break on any filenames containing whitespace or special characters. See:
Why is looping over find's output bad practice?)
If you want your script to be portable, you should stick to POSIX specified features whenever possible. In particular the -executable primary to find is not specified by POSIX. Consider using -perm +700 instead.
Also in the realm of portability, using the "append" command to Sed (a) without a following <newline> sequence works in GNU Sed, but is not standard.
You set the file variable in your for loop to the name of each file in turn (assuming no special characters or whitespace in the filenames, which will cause the file variable to contain something which is not a filename), but you never actually use the file variable.
Your Sed command is not given any file to run on, so it will attempt to run on standard input. Thus when you run the script it will simply wait for input.
Your Sed script itself is incorrect, independent of the fact that it's missing a filename to operate on.
If you use / as a delimiter for a regex (which is most usual), you need to backslash-escape all instances of / which occur within the regex. The only portion of your command which will be read as a regex is /#!/, and the rest (starting with bin) will be interpreted as a Sed command.
Instead, the usual solution would be to replace each / other than the final regex delimiter with /. (I see that you escaped only the last slash, which should not be escaped.)
There is a little-known feature in Sed, which you could use to your advantage here. Any character (other than a backslash or newline) can be used as a regex delimiter, rather than only using a slash. So rather than using /#!/bin/bash/ as a Sed address, you could use the equivalent :#!/bin/bash:
Now if you've handled all of the above points, you will have a working script. It may not do what you want it to do, but it will actually do something. Such a script would look like this:
#!/bin/bash
find . -type f -perm -700 -exec sed ':#!/bin/bash:a
Hello World' +
What does this script do? It searches the current directory recursively for all files with the executable bit set (for the owner), and for each such file, prints the entire file with the text Hello World appended after any lines which contain the text #!/bin/bash.
Sed is not actually designed for editing files in place; it is the Stream EDitor. GNU Sed will allow you to edit files in place using the -i switch, but I would just use the standard tool ex for file editing.
But there is another point here. If you want to add the line Hello World in a Bash script, it won't actually do anything, as Hello is not a valid command name. Perhaps what you want is to print the text "Hello World" in the Bash script, in other words to add echo "Hello World, which could make sense.
Now we're into the realm of clarifying more exactly what your script is supposed to do.
The Final Script
So my more exact statement of the specifications for this script are:
- The script shall find all regular files in the current directory (or any subdirectory recursively) which have the executable bit set for the owner.
- For each such file, the script shall check whether the first line of the file exactly equals the string
#!/bin/bash. - Only for files with this exact first line, the script shall insert the exact text
echo "Hello World", followed by a newline character, after the first line of the file. (This change shall be saved to the file, not printed to standard out.)
Here is a script matching those exact specifications, using only POSIX tools and features:
#!/bin/sh
find . -type f -perm -700 -exec sh -c '
for f
do
head -n 1 "$f" | grep -qFx "#!/bin/bash" &&
printf "%sn" "1a" "echo "Hello World"" . x | ex "$f"
done
' find-sh +
Hi, when I run this script I got : find: invalid mode ‘+700’
– K.U
Nov 10 '16 at 23:26
I'm using Virtual Machine on MacOs and the version is 4.4.0-45-generic I think.
– K.U
Nov 10 '16 at 23:43
Even it prints out that error the code still append : echo "Hello World" to my executable files
– K.U
Nov 10 '16 at 23:48
@K.U, fixed. Use-700, not+700.
– Wildcard
Nov 11 '16 at 0:04
it appends "echo "Hello World" " instead of just "Hello World". Should I remove one of the " "
– K.U
Nov 11 '16 at 0:10
add a comment |
#!/bin/bash
for file in `find . -type f -executable`;do
sed '/#!/bin/bash/a Hello Word'
fi
done
This script has a great number of problems.
First, it's not a valid Bash script, because you have fi with no corresponding if.
Stylistically (after removing the fi line), I would remove the empty line before done and add a space before do. But that's relatively trivial.
Now, as to best practices, you are using backticks for command substitution rather than the recommended modern form, $(...). Backticks are supported purely for historical reasons and are not recommended for any new scripts; see:
- Have backticks (i.e. `cmd`) in *sh shells been deprecated?
You have a robustness issue in that you are looping over the output of find—a very bad idea, and totally unnecessary. Your script will break on any filenames containing whitespace or special characters. See:
Why is looping over find's output bad practice?)
If you want your script to be portable, you should stick to POSIX specified features whenever possible. In particular the -executable primary to find is not specified by POSIX. Consider using -perm +700 instead.
Also in the realm of portability, using the "append" command to Sed (a) without a following <newline> sequence works in GNU Sed, but is not standard.
You set the file variable in your for loop to the name of each file in turn (assuming no special characters or whitespace in the filenames, which will cause the file variable to contain something which is not a filename), but you never actually use the file variable.
Your Sed command is not given any file to run on, so it will attempt to run on standard input. Thus when you run the script it will simply wait for input.
Your Sed script itself is incorrect, independent of the fact that it's missing a filename to operate on.
If you use / as a delimiter for a regex (which is most usual), you need to backslash-escape all instances of / which occur within the regex. The only portion of your command which will be read as a regex is /#!/, and the rest (starting with bin) will be interpreted as a Sed command.
Instead, the usual solution would be to replace each / other than the final regex delimiter with /. (I see that you escaped only the last slash, which should not be escaped.)
There is a little-known feature in Sed, which you could use to your advantage here. Any character (other than a backslash or newline) can be used as a regex delimiter, rather than only using a slash. So rather than using /#!/bin/bash/ as a Sed address, you could use the equivalent :#!/bin/bash:
Now if you've handled all of the above points, you will have a working script. It may not do what you want it to do, but it will actually do something. Such a script would look like this:
#!/bin/bash
find . -type f -perm -700 -exec sed ':#!/bin/bash:a
Hello World' +
What does this script do? It searches the current directory recursively for all files with the executable bit set (for the owner), and for each such file, prints the entire file with the text Hello World appended after any lines which contain the text #!/bin/bash.
Sed is not actually designed for editing files in place; it is the Stream EDitor. GNU Sed will allow you to edit files in place using the -i switch, but I would just use the standard tool ex for file editing.
But there is another point here. If you want to add the line Hello World in a Bash script, it won't actually do anything, as Hello is not a valid command name. Perhaps what you want is to print the text "Hello World" in the Bash script, in other words to add echo "Hello World, which could make sense.
Now we're into the realm of clarifying more exactly what your script is supposed to do.
The Final Script
So my more exact statement of the specifications for this script are:
- The script shall find all regular files in the current directory (or any subdirectory recursively) which have the executable bit set for the owner.
- For each such file, the script shall check whether the first line of the file exactly equals the string
#!/bin/bash. - Only for files with this exact first line, the script shall insert the exact text
echo "Hello World", followed by a newline character, after the first line of the file. (This change shall be saved to the file, not printed to standard out.)
Here is a script matching those exact specifications, using only POSIX tools and features:
#!/bin/sh
find . -type f -perm -700 -exec sh -c '
for f
do
head -n 1 "$f" | grep -qFx "#!/bin/bash" &&
printf "%sn" "1a" "echo "Hello World"" . x | ex "$f"
done
' find-sh +
#!/bin/bash
for file in `find . -type f -executable`;do
sed '/#!/bin/bash/a Hello Word'
fi
done
This script has a great number of problems.
First, it's not a valid Bash script, because you have fi with no corresponding if.
Stylistically (after removing the fi line), I would remove the empty line before done and add a space before do. But that's relatively trivial.
Now, as to best practices, you are using backticks for command substitution rather than the recommended modern form, $(...). Backticks are supported purely for historical reasons and are not recommended for any new scripts; see:
- Have backticks (i.e. `cmd`) in *sh shells been deprecated?
You have a robustness issue in that you are looping over the output of find—a very bad idea, and totally unnecessary. Your script will break on any filenames containing whitespace or special characters. See:
Why is looping over find's output bad practice?)
If you want your script to be portable, you should stick to POSIX specified features whenever possible. In particular the -executable primary to find is not specified by POSIX. Consider using -perm +700 instead.
Also in the realm of portability, using the "append" command to Sed (a) without a following <newline> sequence works in GNU Sed, but is not standard.
You set the file variable in your for loop to the name of each file in turn (assuming no special characters or whitespace in the filenames, which will cause the file variable to contain something which is not a filename), but you never actually use the file variable.
Your Sed command is not given any file to run on, so it will attempt to run on standard input. Thus when you run the script it will simply wait for input.
Your Sed script itself is incorrect, independent of the fact that it's missing a filename to operate on.
If you use / as a delimiter for a regex (which is most usual), you need to backslash-escape all instances of / which occur within the regex. The only portion of your command which will be read as a regex is /#!/, and the rest (starting with bin) will be interpreted as a Sed command.
Instead, the usual solution would be to replace each / other than the final regex delimiter with /. (I see that you escaped only the last slash, which should not be escaped.)
There is a little-known feature in Sed, which you could use to your advantage here. Any character (other than a backslash or newline) can be used as a regex delimiter, rather than only using a slash. So rather than using /#!/bin/bash/ as a Sed address, you could use the equivalent :#!/bin/bash:
Now if you've handled all of the above points, you will have a working script. It may not do what you want it to do, but it will actually do something. Such a script would look like this:
#!/bin/bash
find . -type f -perm -700 -exec sed ':#!/bin/bash:a
Hello World' +
What does this script do? It searches the current directory recursively for all files with the executable bit set (for the owner), and for each such file, prints the entire file with the text Hello World appended after any lines which contain the text #!/bin/bash.
Sed is not actually designed for editing files in place; it is the Stream EDitor. GNU Sed will allow you to edit files in place using the -i switch, but I would just use the standard tool ex for file editing.
But there is another point here. If you want to add the line Hello World in a Bash script, it won't actually do anything, as Hello is not a valid command name. Perhaps what you want is to print the text "Hello World" in the Bash script, in other words to add echo "Hello World, which could make sense.
Now we're into the realm of clarifying more exactly what your script is supposed to do.
The Final Script
So my more exact statement of the specifications for this script are:
- The script shall find all regular files in the current directory (or any subdirectory recursively) which have the executable bit set for the owner.
- For each such file, the script shall check whether the first line of the file exactly equals the string
#!/bin/bash. - Only for files with this exact first line, the script shall insert the exact text
echo "Hello World", followed by a newline character, after the first line of the file. (This change shall be saved to the file, not printed to standard out.)
Here is a script matching those exact specifications, using only POSIX tools and features:
#!/bin/sh
find . -type f -perm -700 -exec sh -c '
for f
do
head -n 1 "$f" | grep -qFx "#!/bin/bash" &&
printf "%sn" "1a" "echo "Hello World"" . x | ex "$f"
done
' find-sh +
edited Apr 13 '17 at 12:37
Community♦
1
1
answered Nov 10 '16 at 10:13
WildcardWildcard
23.3k1067172
23.3k1067172
Hi, when I run this script I got : find: invalid mode ‘+700’
– K.U
Nov 10 '16 at 23:26
I'm using Virtual Machine on MacOs and the version is 4.4.0-45-generic I think.
– K.U
Nov 10 '16 at 23:43
Even it prints out that error the code still append : echo "Hello World" to my executable files
– K.U
Nov 10 '16 at 23:48
@K.U, fixed. Use-700, not+700.
– Wildcard
Nov 11 '16 at 0:04
it appends "echo "Hello World" " instead of just "Hello World". Should I remove one of the " "
– K.U
Nov 11 '16 at 0:10
add a comment |
Hi, when I run this script I got : find: invalid mode ‘+700’
– K.U
Nov 10 '16 at 23:26
I'm using Virtual Machine on MacOs and the version is 4.4.0-45-generic I think.
– K.U
Nov 10 '16 at 23:43
Even it prints out that error the code still append : echo "Hello World" to my executable files
– K.U
Nov 10 '16 at 23:48
@K.U, fixed. Use-700, not+700.
– Wildcard
Nov 11 '16 at 0:04
it appends "echo "Hello World" " instead of just "Hello World". Should I remove one of the " "
– K.U
Nov 11 '16 at 0:10
Hi, when I run this script I got : find: invalid mode ‘+700’
– K.U
Nov 10 '16 at 23:26
Hi, when I run this script I got : find: invalid mode ‘+700’
– K.U
Nov 10 '16 at 23:26
I'm using Virtual Machine on MacOs and the version is 4.4.0-45-generic I think.
– K.U
Nov 10 '16 at 23:43
I'm using Virtual Machine on MacOs and the version is 4.4.0-45-generic I think.
– K.U
Nov 10 '16 at 23:43
Even it prints out that error the code still append : echo "Hello World" to my executable files
– K.U
Nov 10 '16 at 23:48
Even it prints out that error the code still append : echo "Hello World" to my executable files
– K.U
Nov 10 '16 at 23:48
@K.U, fixed. Use
-700, not +700.– Wildcard
Nov 11 '16 at 0:04
@K.U, fixed. Use
-700, not +700.– Wildcard
Nov 11 '16 at 0:04
it appends "echo "Hello World" " instead of just "Hello World". Should I remove one of the " "
– K.U
Nov 11 '16 at 0:10
it appends "echo "Hello World" " instead of just "Hello World". Should I remove one of the " "
– K.U
Nov 11 '16 at 0:10
add a comment |
what you are trying to achieve ? to find out the executable scripts, use the below command
find . -type f -perm /u+x,g+x,o+x | while read file
do
filename=$(echo $file | awk -F/ 'print $NF')
echo "File Name : $filename"
done
If you are trying append Hello World after the shebang line, then your sed command should be
sed '/#!/bin/bash/a Hello Word' $file
if you want to make the changes in the file itself, then add -i in sed command
Hi, I'm trying to append Hello World to executable files in a directory. I know how to find executable files, but I don't quite know how I could append text to those file
– K.U
Nov 10 '16 at 23:33
When I run your code to find executables file I got: File Name : ./insert.sh Is there a way I can only get: File Name : insert.sh
– K.U
Nov 10 '16 at 23:39
modified the answer
– Kamaraj
Nov 11 '16 at 3:35
add a comment |
what you are trying to achieve ? to find out the executable scripts, use the below command
find . -type f -perm /u+x,g+x,o+x | while read file
do
filename=$(echo $file | awk -F/ 'print $NF')
echo "File Name : $filename"
done
If you are trying append Hello World after the shebang line, then your sed command should be
sed '/#!/bin/bash/a Hello Word' $file
if you want to make the changes in the file itself, then add -i in sed command
Hi, I'm trying to append Hello World to executable files in a directory. I know how to find executable files, but I don't quite know how I could append text to those file
– K.U
Nov 10 '16 at 23:33
When I run your code to find executables file I got: File Name : ./insert.sh Is there a way I can only get: File Name : insert.sh
– K.U
Nov 10 '16 at 23:39
modified the answer
– Kamaraj
Nov 11 '16 at 3:35
add a comment |
what you are trying to achieve ? to find out the executable scripts, use the below command
find . -type f -perm /u+x,g+x,o+x | while read file
do
filename=$(echo $file | awk -F/ 'print $NF')
echo "File Name : $filename"
done
If you are trying append Hello World after the shebang line, then your sed command should be
sed '/#!/bin/bash/a Hello Word' $file
if you want to make the changes in the file itself, then add -i in sed command
what you are trying to achieve ? to find out the executable scripts, use the below command
find . -type f -perm /u+x,g+x,o+x | while read file
do
filename=$(echo $file | awk -F/ 'print $NF')
echo "File Name : $filename"
done
If you are trying append Hello World after the shebang line, then your sed command should be
sed '/#!/bin/bash/a Hello Word' $file
if you want to make the changes in the file itself, then add -i in sed command
edited Nov 11 '16 at 3:35
answered Nov 10 '16 at 8:33
KamarajKamaraj
2,9991514
2,9991514
Hi, I'm trying to append Hello World to executable files in a directory. I know how to find executable files, but I don't quite know how I could append text to those file
– K.U
Nov 10 '16 at 23:33
When I run your code to find executables file I got: File Name : ./insert.sh Is there a way I can only get: File Name : insert.sh
– K.U
Nov 10 '16 at 23:39
modified the answer
– Kamaraj
Nov 11 '16 at 3:35
add a comment |
Hi, I'm trying to append Hello World to executable files in a directory. I know how to find executable files, but I don't quite know how I could append text to those file
– K.U
Nov 10 '16 at 23:33
When I run your code to find executables file I got: File Name : ./insert.sh Is there a way I can only get: File Name : insert.sh
– K.U
Nov 10 '16 at 23:39
modified the answer
– Kamaraj
Nov 11 '16 at 3:35
Hi, I'm trying to append Hello World to executable files in a directory. I know how to find executable files, but I don't quite know how I could append text to those file
– K.U
Nov 10 '16 at 23:33
Hi, I'm trying to append Hello World to executable files in a directory. I know how to find executable files, but I don't quite know how I could append text to those file
– K.U
Nov 10 '16 at 23:33
When I run your code to find executables file I got: File Name : ./insert.sh Is there a way I can only get: File Name : insert.sh
– K.U
Nov 10 '16 at 23:39
When I run your code to find executables file I got: File Name : ./insert.sh Is there a way I can only get: File Name : insert.sh
– K.U
Nov 10 '16 at 23:39
modified the answer
– Kamaraj
Nov 11 '16 at 3:35
modified the answer
– Kamaraj
Nov 11 '16 at 3:35
add a comment |
find . -type f -executable -exec sed '/^#!/bin/bash/a Hello World' ;
add a comment |
find . -type f -executable -exec sed '/^#!/bin/bash/a Hello World' ;
add a comment |
find . -type f -executable -exec sed '/^#!/bin/bash/a Hello World' ;
find . -type f -executable -exec sed '/^#!/bin/bash/a Hello World' ;
answered Nov 10 '16 at 9:59
ewattewatt
37028
37028
add a comment |
add a comment |
Thanks for contributing an answer to Unix & Linux Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f322255%2fappend-to-files%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
2
Have a look at this question. Looping over find's output is a bad practice.
– Iñaki Murillo
Nov 10 '16 at 8:41