I wrote the following assertion in makefile to append to an existing text file. Make file is executed using nmake tool.
TempFile.txt :
>> $# echo Hello World !
copy /Y ExistingFile.txt+TempFile.txt ExistingFile.txt
The above is working but writing an extra character at the end.
Hi There !
Hello World !
-
Extra character is not exactly an - character but the carriage return character SUB. How to avoid it ? Is there any other easy way to append text to an existing file ?
You can append text to the end of an existing file also by using pipes:
TempFile.txt :
>> $# echo Hello World !
type TempFile.txt >> ExistingFile.txt
Related
The final.txt looks like:
build/create_changes.sh
build/create_changes.sh-meta.xml
src/aura/camping/camping.design
src/aura/camping/camping.design-meta.xml
I would like to replace only replace the files which contains /aura/ in its line to src/aura/camping
if [ -e final.txt ]
then
ARRAY=()
while read CFILE
do
echo Analyzing file `basename $CFILE`
case "$CFILE"
in
*.design) TYPENAME="AuraDefinitionBundle";;
*) TYPENAME="UNKNOWN";;
esac
if [ "$TYPENAME" == "AuraDefinitionBundle" ]
then
if [ $(contains "${ARRAY[#]}" $(basename -- "$(dirname -- "$CFILE")")) != "y" ]
then
echo baseFile from new method cFile $CFILE
CFILENAME="$CFILE"
replace="src/aura/"$(basename -- "$(dirname -- "$CFILE")")
echo checkChanges "${CFILENAME/$CFILENAME/"$replace"}"
CFILE="${CFILENAME/$CFILENAME/"$replace"}"
echo baseFile from after change method cFile $CFILE
else
continue
fi
fi
done < final.txt
else
echo Change file not found!
This works, so I can see this in the window now:
[exec] baseFile from new method cFile src/aura/camping/camping.design
[exec] checkChanges src/aura/camping
[exec] baseFile from after change method cFile src/aura/camping
But the file final.txt does not change:
build/create_changes.sh
build/create_changes.sh-meta.xml
src/aura/camping/camping.design
src/aura/camping/camping.design-meta.xml
I replaced it right there CFILE="${CFILENAME/$CFILENAME/"$replace"}"
Tried this too :
if [ $(contains "${ARRAY[#]}" $(basename -- "$(dirname -- "$CFILE")")) != "y" ]
then
CFILENAME="$CFILE"
ARRAY+=($(basename -- "$(dirname -- "$CFILE")"))
replace="src/aura/"$(basename -- "$(dirname -- "$CFILE")")
#CFILE="${CFILENAME/$CFILENAME/"$replace"}"
sed -i 's/$CFILENAME/$replace/' final.txt
else
continue
fi
Am I missing something more here?
Your attempt has been good for the most parts, but the part involving changing the file content is incorrect in both the attempts.
Problem 1
You were surprised that the below attempt did not replace the contents of the file. It won't.
CFILE="${CFILENAME/$CFILENAME/"$replace"}"
Because the above is a bash internal construct for string replacement. It just replaces the string contents stored in the variable CFILENAME and puts the result to CFILE. No file modification is done at all.
Judging from your inputs your CFILENAME input would be src/aura/camping/camping.design and the replace variable would be src/aura/camping. Doing the above would put the string src/aura/camping to the variable CFILE and not to the file pointed by the variable CFILE.
Problem 2
You seemed to have identified that sed would solve your problem, which is in the right track, but you seemed to have missed a couple of tricks.
You have variables defined in your sed search and replacement parts, but the problem is with the quotes. Variables in bash shell don't expand when single quoted but only with double-quotes.
The next problem is with the de-limiter string used in sed, which is by default /. But remember both your source and replacement strings have / present, so sed would not understand what is the original and replacement text. You need to define a de-limiter that is not / and also any meta-character that is not part of your string. I would recommend | in your case
sed "s|$CFILENAME|$replace|" final.txt
Now the biggest problem is with the -i flag in your sed command which means in-place editing of your files whiles. Remember you are reading the file in a loop with a while read construct line by line and now your editing this file after parsing each line. You are messing up with the shell re-direction in a wrong way here. The ideal way would be re-direct your line by line edits to a temporary file and move it to your original file once the loop is done.
sed "s|$CFILENAME|$replace|" final.txt >> temp_final.txt
Something like above using >> which appends to a file. And once the loop is finished, revert to your original file using mv
mv -- temp_final.txt final.txt
Hello I am trying to add data in a file at the end but It doesn´t work I have a final.txt with this content
cat,dog,pig
I use cat file1.txt >> final.txt
but I obtain this
cat,dog,pig,car,plane,boat
and I want
cat,dog,pig
car,plane,boat
is it possible to obtain this?
echo >> final.txt && cat file1.txt >> final.txt
Let's first talk about why your original code is not working, because this is something that can cause problems for you in the future: your original final.txt file did not end with a newline (that is, there was no extra blank line at the end of the file). That is a POSIX standard (see: Why should text files end with a newline?), and many programs will not work properly when dealing with a text file that does not end with a newline.
Thus, from now on it would be advisable to always end your text files with an newline.
Now, to solve the case at hand, you could run this code:
echo >> final.txt && cat file1.txt >> final.txt
That will fix the lack of a newline on the last line of the original text and thus allow the echo command to work as expected (add the data in a new line).
Important note: the echo command, by default (in most Bash versions), will add a newline at the end of whatever it is inserting. Therefore, when you run the command "echo >> final.txt", it will add a newline at the end of the last line. This is a built-in feature of echo, and that is why running the code above "fixes" the lack of a newline on the original file.
Me and a friend are working on a project, and We have to create a script that can go into a file, and replace all occurances of a certain expression/word/letter with another using Sed. It is designed to go through multiple tests replacing all these occurances, and we don't know what they will be so we have to anticipate anything. We are having trouble on a certain test where we need to replace 'l*' with 'L' in different files using a loop. The code that i have is
#!/bin/sh
p1="$1"
shift
p2="$1"
shift
for file in "$#" #for any file in the directory
do
# A="$1"
#echo $A
#B="$2"
echo "$p1" | sed -e 's/\([*.[^$]\)/\\\1/g' > temporary #treat all special characters as plain text
A="`cat 'temporary'`"
rm temporary
echo "$p1"
echo "$file"
sed "s/$p1/$p2/g" "$file" > myFile.txt.updated #replace occurances
mv myFile.txt.updated "$file"
cat "$file"
done
I have tried testing this on practice files that contain different words and also 'l*' But whenever i test it, it deletes all the text in the file. Can someone help me with this, we would like to get it done soon. Thanks
It looks like you are trying to set A to a version of p1 with all special characters escaped. But you use p1 later instead of A. Try using the variable A, and also try setting it without a temporary file:
A=$( echo "$p1" | sed -e 's/\([*.[^$]\)/\\\1/g' )
I have a bunch of files that are incomplete: the last line is missing an EOL character.
What's the easiest way to add the newline, using any tool (awk maybe?)?
To add a newline at the end of a file:
echo >>file
To add a line at the end of every file in the current directory:
for x in *; do echo >>"$x"; done
If you don't know in advance whether each file ends in a newline, test the last character first. tail -c 1 prints the last character of a file. Since command substitution truncates any final newline, $(tail -c 1 <file) is empty if the file is empty or ends in a newline, and non-empty if the file ends in a non-newline character.
for x in *; do if [ -n "$(tail -c 1 <"$x")" ]; then echo >>"$x"; fi; done
Vim is great for that because if you do not open a file in binary mode, it will automatically end the file with the detected line ending.
So:
vim file -c 'wq'
should work, regardless of whether your files have Unix, Windows or Mac end of line style.
echo >> filename
Try it before mass use :)
I'm searching (without success) for a script, which would work as a batch file and allow me to prepend a UTF-8 text file with a BOM if it doesn't have one.
Neither the language it is written in (perl, python, c, bash) nor the OS it works on, matters to me. I have access to a wide range of computers.
I've found a lot of scripts to do the reverse (strip the BOM), which sounds to me as kind of silly, as many Windows program will have trouble reading UTF-8 text files if they don't have a BOM.
Did I miss the obvious?
Thanks!
The easiest way I found for this is
#!/usr/bin/env bash
#Add BOM to the new file
printf '\xEF\xBB\xBF' > with_bom.txt
# Append the content of the source file to the new file
cat source_file.txt >> with_bom.txt
I know it uses an external program (cat)... but it will do the job easily in bash
Tested on osx but should work on linux as well
NOTE that it assumes that the file doesn't already have BOM (!)
I wrote this addbom.sh using the 'file' command and ICU's 'uconv' command.
#!/bin/sh
if [ $# -eq 0 ]
then
echo usage $0 files ...
exit 1
fi
for file in "$#"
do
echo "# Processing: $file" 1>&2
if [ ! -f "$file" ]
then
echo Not a file: "$file" 1>&2
exit 1
fi
TYPE=`file - < "$file" | cut -d: -f2`
if echo "$TYPE" | grep -q '(with BOM)'
then
echo "# $file already has BOM, skipping." 1>&2
else
( mv "${file}" "${file}"~ && uconv -f utf-8 -t utf-8 --add-signature < "${file}~" > "${file}" ) || ( echo Error processing "$file" 1>&2 ; exit 1)
fi
done
edit: Added quotes around the mv arguments. Thanks #DirkR and glad this script has been so helpful!
(Answer based on https://stackoverflow.com/a/9815107/1260896 by yingted)
To add BOMs to the all the files that start with "foo-", you can use sed. sed has an option to make a backup.
sed -i '1s/^\(\xef\xbb\xbf\)\?/\xef\xbb\xbf/' foo-*
If you know for sure there is no BOM already, you can simplify the command:
sed -i '1s/^/\xef\xbb\xbf/' foo-*
Make sure you need to set UTF-8, because i.e. UTF-16 is different (otherwise check How can I re-add a unicode byte order marker in linux?)
As an improvement on Yaron U.'s solution, you can do it all on a single line:
printf '\xEF\xBB\xBF' | cat - source.txt > source-with-bom.txt
The cat - bit says to concatenate to the front of source.txt what's being piped in from the print command. Tested on OS X and Ubuntu.
I find it pretty simple. Assuming the file is always UTF-8(you're not detecting the encoding, you know the encoding):
Read the first three characters. Compare them to the UTF-8 BOM sequence(wikipedia says it's 0xEF,0xBB,0xBF).
If it's the same, print them in the new file and then copy everything else from the original file to the new file.
If it's different, first print the BOM, then print the three characters and only then print everything else from the original file to the new file.
In C, fopen/fclose/fread/fwrite should be enough.
open in notepad. click save-as. under encoding, select "UTF-8(BOM)" (this is under plain "UTF-8").
I've created a script based on Steven R. Loomis's code.
https://github.com/Vdragon/addUTF-8bomb
Checkout https://github.com/Vdragon/C_CPP_project_template/blob/development/Tools/convertSourceCodeToUTF-8withBOM.bash.sh for example of using this script.
in VBA Access:
Dim name As String
Dim tmpName As String
tmpName = "tmp1.txt"
name = "final.txt"
Dim file As Object
Dim finalFile As Object
Set file = CreateObject("Scripting.FileSystemObject")
Set finalFile = file.CreateTextFile(name)
'Add BOM
finalFile.Write Chr(239)
finalFile.Write Chr(187)
finalFile.Write Chr(191)
'transfer text from tmp to final file:
Dim tmpFile As Object
Set tmpFile = file.OpenTextFile(tmpName, 1)
finalFile.Write tmpFile.ReadAll
finalFile.Close
tmpFile.Close
file.DeleteFile tmpName
Here is the batch file I use for this purpose in Windows. It should be saved with ANSI (Windows-1252) encoding for the /p= part.
#echo off
if [%~1]==[] goto usage
if not exist "%~1" goto notfound
setlocal
set /p AREYOUSURE="Adding UTF-8 BOM to '%~1'. Are you sure (Y/[N])? "
if /i "%AREYOUSURE%" neq "Y" goto canceled
:: Main code is here. Create a temp file containing the BOM, then append the requested file contents, and finally overwrite the original file
(echo|set /p=)>"%~1.temp"
type "%~1">>"%~1.temp"
move /y "%~1.temp" "%~1" >nul
#echo Added UTF-8 BOM to "%~1"
pause
exit /b 0
:usage
#echo Usage: %0 ^<FILE_NAME^>
goto end
:notfound
#echo File not found: "%~1"
goto end
:canceled
#echo Operation canceled.
goto end
:end
pause
exit /b 1
You can save the file as e.g. C:\addbom.bat and use the following .reg file to add it to right-click context menu of all files:
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\*\Shell\Add UTF-8 BOM]
[HKEY_CLASSES_ROOT\*\Shell\Add UTF-8 BOM\command]
#="C:\\addbom.bat \"%1\""