可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I need to use bash to insert a line into a python file. This line needs to appear after any initial comments in the the file.
So given the file:
#!/usr/bin/python
# This is just
# an example comment
moo = "cow"
... etc ...
I need a bash command to insert a new line like this:
#!/usr/bin/python
# This is just
# an example comment
NEW LINE GOES HERE
moo = "cow"
... etc ...
I am entirely stumped on how to do this. I have tried looping over the file line by line, but that just ends up being pretty horrific and severely messing up the file's whitespace.
Any suggestions would be great!
Adam
PS. Yes, this is a bit of a weird thing to do, it is for part of a continuous integration build script.
Edit
For the record, the code I was trying was:
insert_setup_code() {
installed=false
tmpfile="/tmp/$RANDOM"
cat "$INSTALL_TO" | while read -d \n l; do
echo "$l" >> $tmpfile
if [[ ! $installed && ! `echo "$l" | grep "^#"` ]]; then
echo "LINE OF CODE HERE" >> $tmpfile
installed=true
fi
done
}
回答1:
I would write:
line="NEW STUFF HERE"
awk -v text="$line" '!/^#/ && !p {print text; p=1} 1' file
The first non-comment line will trigger the block to print the line:
!/^#/
-- line does not start with a hash
!p
-- variable p is not true
回答2:
there you go
my addline
script. add newline
after any initial comments in the filein
and write to fileout
#!/usr/bin/env bash
newline="$1"
filein="$2"
fileout="$3"
added=0
while read -r; do
if ! ((added)) && ! [[ $REPLY =~ ^# ]]; then
printf "%s\n" "$newline" >> "$fileout"
((added++))
fi
printf "%s\n" "$REPLY" >> "$fileout"
done < "$filein"
Use as:
$ bash addline "my new line" "readThisFile" "writeToThisFile"
adjust to your needs :)
example usage to itself:
$ bash addline "# a test comment line" addline foo
$ cat foo
#!/usr/bin/env bash
# a test comment line
newline="$1"
filein="$2"
fileout="$3"
added=0
while read -r; do
if ! ((added)) && ! [[ $REPLY =~ ^# ]]; then
printf "%s\n" "$newline" >> "$fileout"
((added++))
fi
printf "%s\n" "$REPLY" >> "$fileout"
done < "$filein"
Updated faster version:
using wc -l
and sed
to write the rest of the file instead of looping through each line
#!/usr/bin/env bash
newline="$1"
filein="$2"
fileout="$3"
counter=0
while read -r; do
((counter++))
if ! [[ $REPLY =~ ^# ]]; then
printf "%s\n" "$newline" "$REPLY" >> "$fileout"
break
fi
printf "%s\n" "$REPLY" >> "$fileout"
done < "$filein"
sed -n "$counter,$(wc -l < "$filein")p" "$filein" >> "$fileout"
works as before/above
回答3:
you could add the stub, your new line, and remaining stuff as variables in the bash script, i.e.
HEADER="!#/usr/bin/bla bla.."
YOUR_LINE="NEW LINE GOES HERE"
REST="more stuff"
and pipe them into your new script
echo "$HEADER" "$YOUR_LINE" "$REST" > pytonscript.py
i gues the YOUR_LINE
variable is dynamic, but if the HEADER
and REST
are static that should work, if these are dynamic as well, then you could use head
and tail
in combination with wc -l
to calculate what lines should be included
回答4:
FYI, your bash version would go like this
insert_setup_code() {
install_to="$1"
tmp=$(mktemp -t setup)
added=0
while IFS=$'\n' read -r line ; do
printf "$line\n" >> "$tmp"
[ $added = 0 ] && grep -q '^#' <<<"$line" && printf "LINE OF CODE HERE\n" >>"$tmp" && added=1
done < "$install_to"
mv -f "$tmp" "$install_to"
}
But of course additional setps should be taken if you want to preserve metadata on the $install_to
file
回答5:
Using ed
there is no need for a tmp file.
The following code assumes that there are only empty lines or lines beginning with a #
char before the first non-empty line that does not begin with a #
char.
# insert a line just before the first line that does not begin with a '#' char
# skips empty lines and lines containing whitespace characters only
# for more information on ed see http://wiki.bash-hackers.org/howto/edit-ed
cat <<-'EOF' | ed -s file
H
/^[[:space:]]*[^#[:space:]]/i
NEW STUFF HERE
.
wq
EOF
If you insist that the line gets inserted exactly after the initial comments, you can do that as well.
# using FreeBSD ed (on Mac OS X)
cat <<-'EOF' | ed -s file
H
,v/^#/u\
u\
i\
NEW STUFF HERE\
.
wq
EOF
# using sed & ed
# first get the line number of the first line not beginning with a '#' char;
# then use ed for in-place file editing
lno=$(sed -n '/^#/!{=;q;}' file) &&
cat <<-EOF | ed -s file
H
${lno},${lno}i
NEW STUFF HERE
.
wq
EOF
回答6:
Locate the first empty line
$ grep -n -m1 '^$' input | cut -d: -f1
4
Use that line number and change it to some other string, -i
to edit files in place (use with care!)
$ sed -i '4c NEW STUFF HERE' input
$ cat input
#!/usr/bin/python
# This is just
# an example comment
NEW STUFF HERE
moo = "cow"
... etc ...
A different approach is to grep for the first line that do not contain a #
, then the above becomes:
$ grep -n -m1 '^[^#]' input | cut -d: -f1
5
$ sed -i "5i NEW STUFF HERE" input
$ cat input
#!/usr/bin/python
# This is just
# an example comment
NEW STUFF HERE
moo = "cow"
... etc ...
To use a shell variable in a sed-script, use this aproach, where "
allow variables to be expanded
sed "${num}c NEW STUFF HERE" log